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


3

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

一定是犯了一些小错误 - 我是新手!

如果有人能够解释为什么会发生这种情况,那就很有责

脚本:-

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

非常感谢,亚当

Answers:


5

这个脚本为每个原始文件输出三个文件......如果有人能够解释为什么会发生这种情

因为下次运行它时脚本会拾取它的E12-5_F2_NEG-Amended.txt结尾.txt

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

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

或者放在rm *Amended.txt程序的开头。如果你有一个非常大量的文件和一个目录,这在较旧的Unix变种上会很慢。

另一个选择是将文件输出到一个子目录(所以像这样"new/${f%.txt}.Amended.txt"


3

您可以在一行中执行脚本尝试实现的目标:

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))

AFAIK两者之间没有任何性能差异,但我发现bash方式在视觉上更令人愉悦; 更重要的是,我所描述的方式是在POSIX中定义的,因此更具可移植性。仅在bash中(所以如果你需要将脚本移植到另一个shell,不要使用它),在脚本中执行此操作的最佳方法是使用let:

let noOfRows-=5

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

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

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


1
$(())方法是POSIX,它实际上是对let是非标准的Bash加入法。expr函数的定义也不如POSIX $(())结构,因此如果需要可移植性,后者应该是首选(这通常是良好的脚本和避免坏习惯的良好指导)。例如参见wiki.bash-hackers.org/commands/builtin/...
Daniel Andersson 2013年

@Daniel感谢您的信息,并将其纳入答案
evilsoup 2013年

优秀的批评,我同意它的每一点,但你省略了实际回答原始问题(“为什么有三重输出”)。请参阅@ RedGrittyBrick的答案
kopischke 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.