【问题标题】:Adding numbers in text file using awk and Bash使用 awk 和 Bash 在文本文件中添加数字
【发布时间】:2017-03-19 10:25:44
【问题描述】:

我需要将出现在图书索引中的所有数字加上 22。索引数据如下所示(例如):

Ubuntu, 120, 143, 154
Yggdrasil, 144, 170-171
Yood, Charles, 6
Young, Bob, 178-179
Zawinski, Jamie, 204

我正在尝试使用此脚本通过 awk 执行此操作:

#!/bin/bash

filename="index"
while read -r line
do
    echo $line | awk -v n=22 '{printf($1)}{printf(" " )}{for(i=2;i<=NF;i++)printf(i%2?$i+n:$i+n)", "};{print FS}'
done < "$filename"

它接近工作,但有以下问题:

  1. 它不适用于属于某个范围的页码(例如“170-171”)而不是单个数字。
  2. 对于索引词超过一个词的条目(例如,“X Windows”和“Young, Bob”),输出仅显示词中的第一个词。第二个单词最终输出为数字 22。(我知道为什么会这样——我的 awk 命令将 $2 视为一个数字,如果它是一个字符串,它假定它的值为 0)但我想不通解决方法。

披露:我绝不是 awk 专家。我只是在寻找一种快速的方法来修改我的索引中的页码(几天后到期),因为我的出版商决定在我准备好索引之后更改手稿中的页码。 awk 对我来说似乎是完成这项工作的最佳工具,但如果有人有更好的想法,我愿意接受其他建议。基本上,我只需要一种方式来表示“取此文件中的所有数字并将其加 22;不要更改任何其他内容。”

【问题讨论】:

    标签: bash awk


    【解决方案1】:

    使用 GNU awk 进行多字符 RS 和 RT:

    $ awk -v RS='[0-9]+' '{ORS=(RT=="" ? "" : RT+22)}1' file
    Ubuntu, 142, 165, 176
    Yggdrasil, 166, 192-193
    Yood, Charles, 28
    Young, Bob, 200-201
    Zawinski, Jamie, 226
    

    【讨论】:

    • 我测试了您的解决方案并且非常出色。但 ORS=RT+22 似乎也一样......对吧?
    • 谢谢。不,这将在输出的 enc 处打印22,因为当文件末尾的 RT 为 null 时,它将 ORS 设置为 null + 22。
    【解决方案2】:

    例如:

    perl -plE 's/\b(\d+)\b/$1+22/ge' index
    

    输出

    Ubuntu, 142, 165, 176
    Yggdrasil, 166, 192-193
    Yood, Charles, 28
    Young, Bob, 200-201
    Zawinski, Jamie, 226
    

    但不是awk

    【讨论】:

    • 整洁漂亮。唯一可能的陷阱是标题还包含一个数字(即 Sed 和 Awk 100 hacks : 100 will be done 122)
    • @GeorgeVasiliou 是真的! :) 也会改变每一个 LaTEX 的字体大小等等... ;)
    • 太棒了! Perl 也可以。谢谢。这对我有用。感谢大家的回复——awk 脚本也很有意义,但我喜欢这种优雅的单行 Perl 解决方案,因为它很简单。
    【解决方案3】:

    你可以使用这个 gnu awk 命令:

    awk 'BEGIN {FS="\f";RS="(, |-|\n)";} /^[0-9]+$/ {$1 = $1 +22} { printf("%s%s", $1, RT);}' yourfile
    
    • FSRS 存在一些滥用,以使 awk 将每行中的每个标记作为 它自己的记录处理,因此您不必遍历 字段并测试每个字段是否为数字
    • RS="(, |-|\n)" 配置破折号、换行符和“,”作为记录分隔符
    • 在仅由数字组成的“记录”上:添加了 22
    • printf 打印令牌及其RT 以从文件中重建行

    【讨论】:

      【解决方案4】:

      考虑使用以下awk 脚本(add_number.awk):

      BEGIN{ FS=OFS=", "; if (!n) n=22; }  # if `n` variable hasn't been passed the default is 22
      {
          for (i=1;i<=NF;i++) {      # traversing fields
              if ($i~/^[0-9]+$/) {   # if a field contains a single number
                  $i+=n;
              }  
              else if (match($i, /^([0-9]+)-([0-9]+)$/, arr)) {  # if a field contains `range of numbers`
                  $i=arr[1]+n"-"arr[2]+n;
              } 
          }
          print;
      }
      

      用法:

      awk -v n=22 -f add_number.awk testfile
      

      输出:

      Ubuntu, 142, 165, 176
      Yggdrasil, 166, 192-193
      Yood, Charles, 28
      Young, Bob, 200-201
      Zawinski, Jamie, 226
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-25
        • 2017-01-03
        • 1970-01-01
        • 2012-03-19
        • 2012-10-22
        • 2015-04-01
        • 2014-09-04
        • 2017-07-09
        相关资源
        最近更新 更多