Joe*_*oks 6 bash parsing text-files cat
我试图循环文本文件的目录,并将它们组合成一个文档.这很好用,但文本文件包含代码片段,我的所有格式都被折叠到左侧.一条线上的所有前导空格都被剥离.
#!/bin/sh
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
echo "Processing $f file..."
echo "">$OUTPUT
cat $f | while read line; do
echo "$line">>$OUTPUT
done
echo >>$OUTPUT
echo >>$OUTPUT
done
Run Code Online (Sandbox Code Playgroud)
我当然是一个bash noob,但经过高低搜索我无法找到合适的解决方案.显然,BASH一般都讨厌领先的白色空间.
Gor*_*son 40
正如其他人所指出的那样,使用cat或awk而不是read-echo循环是一种更好的方法 - 避免空白修剪问题(还有其他一些你没有偶然发现),运行速度更快,并且至少与cat一起,只是简洁的代码.尽管如此,我还是希望让read-echo循环正常工作.
首先,空白修剪问题:read命令自动修剪前导和尾随空格; 这可以通过将IFS变量设置为空来更改其空白定义来修复.另外,read假定行尾的反斜杠意味着下一行是一个延续,并且应该与这一行拼接在一起; 要解决此问题,请使用其-r(raw)标志.这里的第三个问题是echo的许多实现解释了字符串中的转义序列(例如,它们可以将\n转换为实际的换行符); 解决这个问题,请改用printf.最后,就像一般的脚本卫生规则一样,当你实际上不需要时,你不应该使用cat; 改为使用输入重定向.通过这些更改,内部循环如下所示:
while IFS='' read -r line; do
printf "%s\n" "$line">>$OUTPUT
done <$f
Run Code Online (Sandbox Code Playgroud)
...周围的脚本还有一些其他问题:尝试将FILES定义为可用.textile文件列表的行在其周围有引号,这意味着它永远不会扩展为实际的文件列表.执行此操作的最佳方法是使用数组:
FILES=(../best-practices/*.textile)
...
for f in "${FILES[@]}"
Run Code Online (Sandbox Code Playgroud)
(并且所有出现的$ f都应该是双引号,以防任何文件名中包含空格或其他有趣的字符 - 也应该使用$ OUTPUT执行此操作,尽管因为在脚本中定义了它实际上是安全的离开.)
最后,有一个echo "">$OUTPUT接近文件循环的顶部,每次都要删除输出文件(即最后,它只包含最后一个.textile文件); 这需要在循环之前移动到.我不确定这里的意图是在文件的开头放一个空行,还是在文件之间放置三个空行(一个在开头,两个在结尾),所以我不确定究竟是什么适当的替代品是.无论如何,在解决所有这些问题之后,我可以解决这个问题:
#!/bin/sh
OUTPUT="../best_practices.textile"
FILES=(../best-practices/*.textile)
: >"$OUTPUT"
for f in "${FILES[@]}"
do
echo "Processing $f file..."
echo >>"$OUTPUT"
while IFS='' read -r line; do
printf "%s\n" "$line">>"$OUTPUT"
done <"$f"
echo >>"$OUTPUT"
echo >>"$OUTPUT"
done
Run Code Online (Sandbox Code Playgroud)
代替:
cat $f | while read line; do
echo "$line">>$OUTPUT
done
Run Code Online (Sandbox Code Playgroud)
做这个:
cat $f >>$OUTPUT
Run Code Online (Sandbox Code Playgroud)
(如果您需要逐行执行操作有原因,最好将其包含在问题中。)