【问题标题】:Pad a specific column with escape characters in Bash在 Bash 中用转义字符填充特定列
【发布时间】:2017-02-02 21:37:41
【问题描述】:

我有一个由数据行组成的文件,其中的列由给定的分隔符指定。

例如

20170202,ABC,USD,USD,100,20170202
20170202,ABC,GBP,USD,200,20170202
20170201,ABC,NOK,USD,300,20170204
20170131,ABC,DKK,USD,400,20170202

我想要一种打印此文件行的方法,例如,第 1 列是 20170202,第 4 列是美元。同时,我想用转义字符包围打印输出中的这些列,以向用户突出显示它们。

所以在上面的例子中,应该只打印第 1 行和第 2 行,并且:

  • 应突出显示第 1 列(但不是第 6 列)
  • 应突出显示第 4 列(但不是第 3 列)

目前我有一个链式 grep 用于传递的每个参数。

例如

cat myfile.txt | grep -w "20170202" | grep -w "USD"

然后将其通过管道传输到 sed 语句,该语句使用转义字符填充 20170202 和 USD 以着色输出。

但是,在上面的示例中,第 4 行将失败,因为它将被错误地输出,第 4 列和第 6 列突出显示。第 1 行也失败,第 1、3、4 和 6 列将突出显示(当我只需要 1 和 4 时)。

谁能建议如何为任意选择的列执行此操作?

包括 awk,因为我认为解决方案可能涉及到它。

【问题讨论】:

    标签: bash unix awk sed grep


    【解决方案1】:

    awk 中,您可以将字段替换为彩色字段。下面的脚本应该 做好本职工作

    # cat 42000109
    1. 20170202,ABC,USD,USD,100,20170202
    2. 20170202,ABC,GBP,USD,200,20170202
    3. 20170201,ABC,NOK,USD,300,20170204
    4. 20170131,ABC,DKK,USD,400,20170202
    
    # awk -v FS=" |," '$2=="20170202" && $4=="USD"{$2="\033[1;31m"$2"\033[1;39m";$4="\033[1;31m"$4"\033[1;39m";print}' 42000109
    
    1. 20170202 ABC USD USD 100 20170202
    #fields 2 and 4 will be highlighted
    

    有关 bash 颜色的更多提示,请查看[ this ] 链接。

    编辑

    如果开头的数字不存在,那么下面的东西应该做

    # awk -v FS=',' -v OFS=',' '$1=="20170202" && $4=="USD"{$1="\033[1;31m"$1"\033[1;39m";$4="\033[1;31m"$4"\033[1;39m";print}' 42000109
    20170202,ABC,USD,USD,100,20170202
    20170202,ABC,GBP,USD,200,20170202
    # #fields 1 and 4 will be highlighted
    

    【讨论】:

    • 对不起,每行开头的 1. 2. 3. 4. 只是为了澄清。这些在实际文件中不存在。鉴于此,您的答案有何变化?
    • 感谢您的帮助
    • 可以使用-F,设置FS,而不是-v FS=,
    【解决方案2】:

    考虑先构建一张你想要的颜色的地图,然后使用它,例如:

    $ cat tst.awk
    BEGIN {
        n = split("\
            red     31 \
            green   32 \
            reset   39 \
                ", tmpA)
        for (i=1; i<=n; i+=2) {
            colors[tmpA[i]] = ("\033[1;" tmpA[i+1] "m")
        }
        FS=OFS=","
    }
    
    function color(field,clr) {
        $field = (colors[clr] $field colors["reset"])
    }
    
    ($1=="20170202") && ($4=="USD") {
        color(1,"red")
        color(4,"green")
    }
    
    { print }
    
    $ awk -f tst.awk file | cat -v
    ^[[1;31m20170202^[[1;39m,ABC,USD,^[[1;32mUSD^[[1;39m,100,20170202
    ^[[1;31m20170202^[[1;39m,ABC,GBP,^[[1;32mUSD^[[1;39m,200,20170202
    20170201,ABC,NOK,USD,300,20170204
    20170131,ABC,DKK,USD,400,20170202
    

    【讨论】:

    • 这对于我所要求的来说是过度设计的。 sjsam 的回答就足够了,我相信在发布时已经标记为正确。无论如何谢谢(有错误的用户,所以推荐)
    • 在一个被标记为正确之后提供不同的答案并没有错。接受的答案有时完全是错误的(在这种情况下不是),而且通常不是最好的答案。这个论坛是供人们搜索问题的答案,而不是只为您提供特定问题的答案,因此虽然您可能会发现这对于您的特定示例来说是过度设计的,但它为您的一般问题提供了通用解决方案描述并记住大多数人在发布问题时会尽量减少他们的实际问题,因此一般解决方案通常比最小解决方案更可取。
    • ^1 不错,回复也不错
    【解决方案3】:

    使用 sed(对于所有这些 \ 来说有点难以阅读)

    sed -e '/^\(20170202\)\(,\([^,]*,\)\{3\}\)\(USD\)\(,.*\)/!d' -e 's//\\\1\\\2\\\4\\\5/' YourFile
    
    # OR into a more generic form
    sed -e '/^\('${YourDate}'\)\(,\([^,]*,\)\{3\}\)\('${YourCurrency}'\)\(,.*\)/!d' -e 's//\\\1\\\2\\\4\\\5/' YourFile
    

    awk 版本

    awk '$1=="20170202"&&$4=="USD"{$1="\\"$1"\\";$4="\\"$4"\\";print}' FS=',' OFS=',' YourFile
    

    相同,更通用,带注释(使用变量进行批处理)

    awk -v MyDate="{YourDate}" -v MyCur="${YourCurrency} '
       # Parameter assign some variable with external value of script
    
       # if first field (col) = the date AND 4th field = Currency
       $1 == MyDate && $4 == MyCur {
          # replace field 1 by itself surrounded by escape char
          $1 = "\\" $1 "\\"
          # same for field 4
          $4 = "\\" $4 "\\"
    
          # Print line (with new content)
          # default output is modified by OFS value adapted (default is space separator between field and set to , in this script)
          print 
          }
       # assign 2 varible (FS and OFS for field separator as input and output)
       # before reading first availble file (YourFile)
       ' FS=',' OFS=',' YourFile
    

    【讨论】:

      【解决方案4】:
      cat text file| awk -F "," '$1 ~ /20170202/ && $3 == "USD"  { print }'
      

      awk 将分隔符逗号“,”用于当前文件并将它们拆分,可以通过 $1、$2、$3 等访问。因此,我们可以根据需要尝试查看 $1 和 $3 的匹配是否为真。 $1 匹配是通过正则表达式匹配完成的,该匹配是通过运算符 ~ 完成的,正则表达式字符串用正斜杠 / 保存。

      【讨论】:

      • 虽然这段代码 sn-p 可以解决问题,包括说明 如何为什么 这解决了问题 would really help 以改进你的帖子质量。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人!请edit您的答案添加解释,并说明适用的限制和假设。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      • 1970-01-01
      • 2021-12-13
      • 2019-10-26
      • 1970-01-01
      • 2018-08-04
      • 1970-01-01
      相关资源
      最近更新 更多