【问题标题】:Sed/awk: Aligning words in a filesed/awk:对齐文件中的单词
【发布时间】:2018-02-02 12:44:45
【问题描述】:

我有一个结构如下的文件:

# #################################################################
#   TEXT: MORE TEXT
#   TEXT: MORE TEXT
# #################################################################

___________________________________________________________________
ITEM 1
___________________________________________________________________
PROPERTY1:     VALUE1_1
PROPERTY222:   VALUE2_1
PROPERTY33:    VALUE3_1
PROPERTY4444:  VALUE4_1
PROPERTY55:    VALUE5_1

Description1:  Some text goes here
Description2:  Some text goes here

___________________________________________________________________
ITEM 2
___________________________________________________________________
PROPERTY1:     VALUE1_2
PROPERTY222:   VALUE2_2
PROPERTY33:    VALUE3_2
PROPERTY4444:  VALUE4_2
PROPERTY55:    VALUE5_2

Description1:  Some text goes here
Description2:  Some text goes here

我想在文件中添加另一个项目,使用 sed 或 awk:

 sed -i -r "\$a$PROPERTY1:     VALUE1_3" file.txt
 sed -i -r "\$a$PROPERTY2222:     VALUE2_3" file.txt

等等。所以我的下一个项目是这样的:

___________________________________________________________________
ITEM 3
___________________________________________________________________
PROPERTY1:     VALUE1_3
PROPERTY222:     VALUE2_3
PROPERTY33:     VALUE3_3
PROPERTY4444:     VALUE4_3
PROPERTY55:     VALUE5_3

Description1:  Some text goes here
Description2:  Some text goes here

values 列是锯齿状的。如何像以前的项目一样将我的值左对齐?我可以在这里看到 2 个解决方案:

  1. 在将值插入文件时对齐值。
  2. 按照我的方式将值插入到文件中,然后对齐它们。

命令

sed -i -r "s|.*:.*|&|g" file.txt

捕获我想要对齐的属性和值,但我无法正确对齐它们,即

awk '/^.*:.*$/{ printf "%-40s %-70s\n", $1, $2 }' file.txt

它打印出文件,但它包含描述值和标签,如果它们包含空格或破折号,则删除这些值。真是一团糟。

根据我在 Stack Overflow 和一些博客上找到的内容,我尝试了更多命令,但没有什么能满足我的需要。

注意:描述标签的值不是锯齿状的——这是因为我以单独的方式将它们写入文件。

我的命令有什么问题?如何实现我的需要?

【问题讨论】:

  • 虽然这可以使用 sed/awk 解决,但使用更强大的工具可能更容易解决。您是否考虑过使用具有适当数据结构的成熟编程语言(例如 perl、ruby、c++)来解决您的问题?
  • @Heinrich,我想避免使用成熟的编程语言,因为我在 bash 中有一个几乎完整的脚本,它完全符合我的要求,这是它唯一的问题。由于这个(不那么严重)问题,我不想强​​迫我的脚本用户安装不同语言的编译器或解释器。

标签: linux bash awk sed text-processing


【解决方案1】:

当你的文件没有标签时,试试这个:

sed -r 's/: +/:\t/' file.txt | expand -20 

当这工作时,将输出重定向到一个 tmpfile 并将 tmpfile 移动到file.txt

【讨论】:

    【解决方案2】:

    您需要做的就是在插入新行时记住现有的缩进,例如:

    echo 'PROPERTY732:    VALUE9_8_7' |
    awk -v prop="PROPERTY1" -v val="VALUE1_3" '
            match($0,/^PROPERTY[^[:space:]]+[[:space:]]+/) { wid=RLENGTH }
            { print }
            END { printf "%-*s%s\n", wid, prop":", val }
        '
    PROPERTY732:    VALUE9_8_7
    PROPERTY1:      VALUE1_3
    

    但不清楚一次添加 1 行是否有意义,或者您添加的所有其他文本来自何处。

    以上内容适用于任何 UNIX 系统上的任何 awk。

    如果您的“属性”实际上并非以“属性”一词开头,那么您只需要编辑您的问题以显示更真实的示例输入/输出,并告诉/向我们展示如何区分属性行和描述行,并且,同样,使用 awk 解决方案将是微不足道的。

    【讨论】:

      【解决方案3】:

      您可以使用 gensub 和周到的字段分隔符来处理这个问题:

      for i in {1..5}; do
          echo $(( 10 ** i )): $i;
      done | awk -F ':::' '/^[^:]+:.+/{
          $0 = gensub(/: +/, ":::", $0 );
          key=( $1 ":" );
          printf "%-40s %s\n", key, $2;
      }'
      

      相关部分是我们将“:+”换成“:::”,然后执行 printf 将其重新组合在一起。

      【讨论】:

      • 您错误地调用了 gensub()(您正在使用 $0 填充“多少替换”字段),您不需要围绕字符串连接的括号,您不需要尾随换行符,我无法想象将 : + 更改为 ::: 并将 FS 设置为 ::: 应该做什么,而不是仅仅将 FS 设置为 : + (谁会说 ::: 不存在于 VALUE ?) 或者只使用几个 sub()s。哦,由于使用了gensub(),你应该提到它是特定于 gawk 的。
      【解决方案4】:

      您可以使用 \t 插入制表符(而不是空格,这就是您获得“锯齿状”值的原因)

      而不是

      sed -i -r "\$a$PROPERTY1:     VALUE1_3" file.txt
      

      使用

      sed -i -r "\$a$PROPERTY1:\t\tVALUE1_3" file.txt
      

      【讨论】:

      • 当一个键的长度为例如两个制表符(加上一些空格)长,另一个键是三个制表符(同样,加上一些空格)长。
      • @M.B.插入制表符或空格都没关系。属性名称的长度不同,所以我总是会得到锯齿状的值。
      猜你喜欢
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多