【问题标题】:increment values in column within file with bash, sed and awk使用 bash、sed 和 awk 增加文件内列中的值
【发布时间】:2014-03-21 13:28:37
【问题描述】:

请在下面找到我的一个文件的摘录。

1991;1;-7;-3;-9;-4;-7
1991;1;-7;-3;-9;-4;-7
1991;1;-7;-3;-9;-4;-7
1991;2;-14;-11;-14;-4;-14
1991;2;-14;-11;-14;-4;-14
1991;2;-14;-11;-14;-4;-14
1991;3;-7;-3;-15;5;-7
1991;3;-7;-3;-15;5;-7
1991;3;-7;-3;-15;5;-7
1991;4;-15;-9;-21;1;-16
1991;4;-15;-9;-21;1;-16
1991;4;-15;-9;-21;1;-16
1992;1;-12;-6;-19;-2;-12
1992;1;-12;-6;-19;-2;-12
1992;1;-12;-6;-19;-2;-12
1992;2;-16;-7;-22;-12;-15
1992;2;-16;-7;-22;-12;-15
1992;2;-16;-7;-22;-12;-15
1992;3;-22;-15;-25;-16;-24
1992;3;-22;-15;-25;-16;-24

只要第一列中的年份保持不变,我正在尝试通过 sed 或/和 awk 在第二列的第二列为第二行添加 + 1。

结果如下:

1991;1;-7;-3;-9;-4;-7
1991;2;-7;-3;-9;-4;-7
1991;3;-7;-3;-9;-4;-7
1991;4;-14;-11;-14;-4;-14
1991;5;-14;-11;-14;-4;-14
1991;6;-14;-11;-14;-4;-14
1991;7;-7;-3;-15;5;-7
1991;8;-7;-3;-15;5;-7
1991;9;-7;-3;-15;5;-7
1991;10;-15;-9;-21;1;-16
1991;11;-15;-9;-21;1;-16
1991;12;-15;-9;-21;1;-16
1992;1;-12;-6;-19;-2;-12
1992;2;-12;-6;-19;-2;-12
1992;3;-12;-6;-19;-2;-12
1992;4;-16;-7;-22;-12;-15
1992;5;-16;-7;-22;-12;-15
1992;6;-16;-7;-22;-12;-15
1992;7;-22;-15;-25;-16;-24
1992;8;-22;-15;-25;-16;-24

我在 stackflow 上看到了无数示例,但没有什么可以让我接近解决方案。

我欢迎任何建议。

最好的,

【问题讨论】:

  • 编辑文件中第一年(1991)的行?
  • 嗨,我不太明白......
  • 编辑所有年份还是只编辑一年?
  • 多年来,嫌疑犯。我正在考虑使用 FOR 循环,它会解析一年,然后使用 "awk -F\| '{++$2;print}'"
  • 当您实际上并不关心使用哪种工具,或者有理由相信任何特定工具适合用例时,为什么要列出特定工具(sed、awk)?如果您想要使用标准 shell 工具的解决方案,请指定“标准 shell 工具”,而不是假设特定工具可以解决问题。

标签: bash sed awk


【解决方案1】:

如果您总是希望年份第一次出现在第 1 列中的那一行的第 2 列为 1,那么:

awk -F\; '$1!=l{c=0}{$2=++c}{l=$1}1' OFS=\; input

如果您想保留第 2 列中的内容:

awk -F\; '$1!=l{c=$2}{$2=c++}{l=$1}1' OFS=\; input

【讨论】:

  • +1,简洁。我通常更喜欢可读性,但最好有一个正确的答案来展示 awk 的优势。
  • 威廉,您的解决方案运行良好。非常感谢您的帮助。
【解决方案2】:

这可以用 awk 更简洁地完成,但是纯 bash 可以正常工作:

last_year=
counter_val=
while IFS=';' read -r year old_counter rest; do
  if [[ $year = "$last_year" ]]; then
    (( ++counter_val ))
  else
    counter_val=1
    last_year=$year
  fi
  printf -v result '%s;' "$year" "$counter_val" "$rest"
  printf '%s\n' "${result%;}"
done <input.txt >output.txt

【讨论】:

  • Charles,我试过你的命令行,但它不起作用......运行 while 循环时它给了我“无效的算术错误”。
  • @AndyK,这不是 bash 中实际存在的错误消息。你确定你复制正确吗?另外,您确定您的脚本实际上以#!/bin/bash 开头,而不是#!/bin/sh? (如果你有一个以#!/bin/bash 开头的脚本,但你用sh scriptname 运行它,那会导致同样的问题)
  • @AndyK,哦。确实在那里发现了一个错误——需要在 IFS 值周围加上引号。现在再试一次,使用IFS=';' 而不是IFS=;
  • 我已经尝试过了,没有将它放入 shell 脚本中。让我在适当的 shell 脚本中再试一次。感谢您的反馈,查尔斯。
  • 这是我在 bash shell 中运行后得到的 ./test_toto.sh &lt; toto2_rev.csv &gt; toto3_rev.csv ./test_toto.sh: line 6: ((: Ann▒e: erreur de syntaxe : opérateur arithmétique non valable (error token is "▒e") ./test_toto.sh: line 6: ((: Ann▒e: erreur de syntaxe : opérateur arithmétique non valable (error token is "▒e") ./test_toto.sh: line 6: ((: Libell▒: erreur de syntaxe : opérateur arithmétique non valable (error token is "▒")
【解决方案3】:

您只是想增加第二列,而不是增加一列?无论第二列是什么,您都希望第二列从一开始吗?

awk -F\; '{
    if ( NR == 1 ) {
        year = $0
    }
    if ( year == $0 ) {
        for (count = 1; count < NF; count++) {
            if ( count == 2) {
                printf NR ";";
            }
            else {
                printf $count ";";
            }
        }
        print "";
    }
    else {
        print 
    }
}' test.txt

Awk 是一个使用自然的程序,因为它在假设循环中运行。另外,它的数学比普通的 shell 更自然。

NR 表示记录数NF 表示字段数。一个字段由我的-F\; 参数分隔,记录是我文件中的行号。程序的其余部分非常明显。

【讨论】:

  • 很好的答案,但我对评论有些不同意——因为指定的 shell 是 bash,它具有完全自然的整数数学;只要您处于数学环境中(使用(( ))),您就拥有与C 相同的所有运算符——甚至是三元运算符。这同样适用于 ksh 和 POSIX sh,除了后者需要使用 $(( ));整数数学在 shell 中的表现已经很糟糕了。
  • 大卫,test.txt 是输入文件。我的猜测正确吗?
  • 是的。我抓取了您的数据并将其放入名为 text.txt 的文件中。
  • 感谢您的反馈。再次检查。
  • 我再次尝试使用我的文件以及文件中的摘录,但它不起作用......
【解决方案4】:

使用 awk,将 FS(字段分隔符)和 OFS(输出字段分隔符)设置为 ';'和 对于每个新年记录,将 val 计数器设置为开始列 2 的值。与那一年的每一行递增val

awk -F';' 'BEGIN{OFS=";";y=0} 
 { if (y!=$1) 
      {y=$1;val=$2;print} 
   else 
      {val++;print $1,val,$3,$4,$5,$6,$7}}' data_file

【讨论】:

  • 您的解决方案运行良好,怀疑者。非常感谢您第一个回答。
  • 鉴于所有其他答案,我必须感谢您验证它是否有效! :)
  • 永远,嫌疑犯,永远。我重视你的工作和其他贡献者的工作,我正在学习。没有工作就像雨中的一滴水,它是独一无二的。 ;)
猜你喜欢
  • 1970-01-01
  • 2013-01-07
  • 2014-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
  • 2019-02-20
相关资源
最近更新 更多