删除一系列文本文件最后 5 行的非常简单的脚本

删除一系列文本文件最后 5 行的非常简单的脚本

由于某种原因,该脚本为每个原始文件输出三个文件,而不是一个。

肯定是犯了一些微不足道的错误——我对此还不熟悉!

如果有人能解释为什么会发生这种情况,我将不胜感激。

脚本:-

for f in *.txt
do
   noOfRows=$(cat $f | wc -l)
   relevantRows=$(expr $noOfRows - 5)
   head -n $relevantRows $f | tee ${f%.txt}-Amended.txt
done

ls 命令的结果:-

E12-5_F2_NEG-Amended-Amended-Amended.txt  E12-5_M3_POS-Amended-Amended-Amended.txt
E12-5_F2_NEG-Amended-Amended.txt          E12-5_M3_POS-Amended-Amended.txt
E12-5_F2_NEG-Amended.txt                  E12-5_M3_POS-Amended.txt
E12-5_F2_NEG.txt                          E12-5_M3_POS.txt
E12-5_F2_POS-Amended-Amended-Amended.txt  E12-5_M4_NEG-Amended-Amended-Amended.txt
E12-5_F2_POS-Amended-Amended.txt          E12-5_M4_NEG-Amended-Amended.txt
E12-5_F2_POS-Amended.txt                  E12-5_M4_NEG-Amended.txt
E12-5_F2_POS.txt                          E12-5_M4_NEG.txt
E12-5_F5_NEG-Amended-Amended-Amended.txt  E12-5_M4_POS-Amended-Amended-Amended.txt
E12-5_F5_NEG-Amended-Amended.txt          E12-5_M4_POS-Amended-Amended.txt
E12-5_F5_NEG-Amended.txt                  E12-5_M4_POS-Amended.txt
E12-5_F5_NEG.txt                          E12-5_M4_POS.txt
E12-5_F5_POS-Amended-Amended-Amended.txt  E12-5_M7_NEG-Amended-Amended-Amended.txt
E12-5_F5_POS-Amended-Amended.txt          E12-5_M7_NEG-Amended-Amended.txt
E12-5_F5_POS-Amended.txt                  E12-5_M7_NEG-Amended.txt
E12-5_F5_POS.txt                          E12-5_M7_NEG.txt
E12-5_M3_NEG-Amended-Amended-Amended.txt  E12-5_M7_POS-Amended-Amended-Amended.txt
E12-5_M3_NEG-Amended-Amended.txt          E12-5_M7_POS-Amended-Amended.txt
E12-5_M3_NEG-Amended.txt                  E12-5_M7_POS-Amended.txt
E12-5_M3_NEG.txt                          E12-5_M7_POS.txt

非常感谢,亚当

答案1

该脚本为每个原始文件输出三个文件...如果有人能解释为什么会发生这种情况,我将不胜感激。

由于以E12-5_F2_NEG-Amended.txt结尾,.txt下次运行时脚本将拾取它。

这三重结果表明您在调试脚本时运行了三次。

如果脚本输出到$f.new而不是${f%.txt}-Amended.txt,则不会遇到这个问题。

或者放在rm *Amended.txt程序的开头。如果目录中有大量文件,则在较旧的 Unix 版本上可能会很慢。

另一个选择是将文件输出到子目录中(类似于"new/${f%.txt}.Amended.txt"

答案2

您只需一行代码即可完成脚本所要实现的功能:

head --lines=-5 input.txt > output.txt

在 for 循环中:

for f in *.txt; do head --lines=-5 "$f" > "${f%.txt}-Amended.txt"; done

如果愿意,您可以使用-n -5而不是来节省输入时间。--lines=-5

正如 RedGrittyBrick 指出的那样,每个输入有三个文件的原因可能是因为您多次运行了该脚本,并且由于输出以 .txt 结尾,因此它们被连续脚本的 *.txt glob 拾取。

现在我将批评你的具体剧本。

noOfRows=$(cat $f | wc -l)

这确实猫的无用用途; 而不是cat $f | wc -l,使用wc -l "$f"。在这个特定的脚本中,这可能不是那么重要,但最好不要养成坏习惯。说到坏习惯:始终引用变量例如"$f"。这将确保文件名即使包含空格也会被视为单个参数。

relevantRows=$(expr $noOfRows - 5)

这里其实没有什么问题,尽管我通常更喜欢使用类似

relevantRows=$((noOfRows-5))

据我所知,两者之间没有性能差异,但我发现 bash 的方式更美观;更重要的是,我描述的方式是在 POSIX 中定义的,因此更便携仅在 bash 中(因此如果您需要将脚本移植到不同的 shell,请不要使用此功能),最好的在脚本中执行此操作的方法是使用 let:

let noOfRows-=5

...这会从变量 $noOfRows 包含的数字中减去 5,这意味着不需要创建变量 $relevantRows。

head -n $relevantRows $f | tee ${f%.txt}-Amended.txt

这是正确的做法如果您希望将输出显示在命令行上,并将其放入输出文件中。否则,只需使用>将 stdout 重定向到文件即可。

相关内容