首页 > 解决方案 > bash中的for循环只是打印n次命令而不是重复

问题描述

我有一个超过 6000 行的 input.txt 文件。

如果一行 a 有超过 10 个单词,那么我希望它被拆分,但不是在第 10 个单词,而是第一个逗号字符出现的位置。并且,如果新行也有超过 10 个单词,那么也应该拆分,并不断重复这个过程 7 次。

最终产品:没有超过 10 个单词和逗号的行,因为它们都已被拆分。

例子:

输入

Line 1: This is me, and my sample test line that I like to get working, and I want to be able to kick some ass while doing it

预期输出:

Line 1: This is me, 
Line 2: and my sample test line that I like to get working,
Line 3: and I want to be able to kick some ass while doing it

我正在使用以下代码:

#! /bin/bash

for run in {1..7}
do

awk 'NF >= 10 {
sub (", ", ",\n")

}1' input.txt

done

此代码没有给出预期的结果。相反,我得到以下输出 7 次。

line 1: This is me,

line 2: and my sample test line that I like to get working, and I want to be able to kick some ass while doing it.

我倾向于sed,但我不清楚。我看到了三种方法 1) 代码读取一行(比如 line7),它超过 10 个单词并以逗号分隔(但不检查新破坏的 like 是否超过 10 个单词)并移至下一行。在文件末尾,它会重复这个过程(比如 7 次)以确保新断行也在 10 个单词以下。然后,它接受这个过程的输出并做同样的事情,但有一个新的条件(例如单词“和”)。然后,它需要这个等的输出......我可以添加无穷无尽的条件。这是我更喜欢的方法。我也认为编码更容易。

第二种方法 2)是代码读取行,如果超过 10 个单词,它会在逗号处分解,然后如果仍然超过 10 个单词,它会在逗号处进一步分解,依此类推,直到少于 10 个单词。只有这样,它才会移动到下一行。我认为这就是 Ghoti 的代码所做的。但是添加附加条件很复杂。3)第三种方法是:它在逗号处分行超过 10 个单词,然后在“and”处分行,以此类推。然后最后,整个过程被重复了几次。恕我直言,这也不是最好的方法。

有人可以帮忙吗。

先感谢您!

标签: linuxbashfor-loop

解决方案


我想我明白你在追求什么。您的方法存在一些问题:

  • awk 不会就地处理文件。所以你sub()做出改变,1打印到标准输出,但你的输入文件永远不会改变。
  • 当 you 时sub(),您不会将新记录插入到 awk 正在处理的输入流中。您的命令只是在当前记录中添加一个换行符。

鉴于这些,您可以按照您的建议多次处理输入。但与其武断地假设一行最多有 7 个 10 字的短语,不如实际检测是否需要继续。像这样的东西:

#!/usr/bin/env bash

input=input.txt
temp=$(mktemp ${input}.XXXX)
trap "rm -f $temp" 0

while awk '
  BEGIN { retval=1 }
  NF >= 10 && /, / {
    sub(/, /, ","ORS)
    retval=0
  }
  1
  END { exit retval }
' "$input" > "$temp"; do
  mv -v $temp $input
done

这使用来自 awk 的退出值来确定我们是否需要运行 bash 循环的另一次迭代。如果 awk 检测到不需要替换,则循环停止。


推荐阅读