在网上搜索后,我能够弄清楚如何逐行阅读文件:
while read p; do
echo $p
done < file.txt
但我真的想修改文件中的行。 例如:
while read p; do
if condition
then
echo $p | perl -i -pe 's/a/b/'
fi
done < file.txt
然而,这并没有实际修改文件。
答案 0 :(得分:1)
更新添加了远更好的bash代码版本。感谢Charles Duffy的评论。
你的Perl one-liner采用echo $p |
传递给它的一条线,以此方式获得标准输入。它对文件本身没有任何作用,因此-i
标志无效。 -p
使其打印到标准输出流。因此,整行echo ...
不会触及文件。
您可以将输出重定向到新文件,然后移动该文件以覆盖file.txt
。这是一个简单的例子,它将每一行附加到一个新文件。有关更好的bash代码,请参阅下面的更新。
while read p; do
if condition
then
echo $p | perl -pe 's/a/b/' >> temp_out.txt
else
echo $p >> temp_out.txt
fi
done < file.txt
mv temp_out.txt file.txt
我们必须添加else
,其中还会附加所有未修改的行。请注意,通常我们不能只更换一些行,但必须重写整个文件。
如果这就是脚本所做的一切,你可以使用一个非常简单的单行程序来完成它,请参阅结尾。如果做了更多的工作,你也可以将它全部放在Perl脚本中,但我认为bash脚本可能有其他充分的理由。
更新上述更好的版本。请参阅Builtins in Bash manual
read
和echo
每次添加行都会重新打开文件,而不需要这样做。 只需在循环结束时重定向,就像在终端
read
使用反斜杠进行转义,将其从输入中删除。请使用-r
删除尾随空白区域,作为将该行划分为单词的一部分。通过取消设置控制用于拆分的字符的变量来解决此问题,IFS=
echo $p
可以做各种无意识的事情。格式化的打印效果更好,printf '%s\n' "$p"
或至少echo "$p"
有了这个,
while IFS= read -r p; do
if condition
then
echo "$p" | perl -pe 's/a/b/'
else
echo "$p"
fi
done < file.txt > temp_out.txt
mv temp_out.txt file.txt
最后,如果Perl one-liner的唯一目的是运行一个简单的替换,那么在shell本身中执行该操作要比拥有一个管道并为每一行运行一个全新的进程要好得多。 / p>
echo "${p//a/b}"
感谢Charles Duffy在评论中提出所有这些要点。
关于Perl one-liners的一些评论。请参阅perlrun
上的文档。
命令perl -e '...'
执行''
之间的任何有效Perl代码。当我们添加-n
或-p
开关时,它还会读取标准输入并在此行的某一行上执行该代码,其中-p
也会在处理完每行后打印出来。标准输入可以从文件
perl -pe '...' input.txt
在这种情况下,添加-i
标志将导致文件就地更改。或者,输入可以通过管道输入,例如
echo "input text" | perl -pe '...'
在这种情况下,处理过的行打印到标准输出。这可以重定向到文件,如上面的答案。
要一次更改给定文件,您只需在命令行
上进行此操作perl -i -pe 's/a/b/' file.txt
如果还有更多工作要做,那么最好将它放在脚本中,当然。在这种情况下,单行也可以是bash脚本中的命令,替换上面的所有代码(除非处理行首选某些特定于bash的功能)。