阅读时保留前导空格>>在bash中逐行写入文件

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)


Lau*_*ves 4

代替:

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)

(如果您需要逐行执行操作有原因,最好将其包含在问题中。)

  • @ehime 请详细说明。 (2认同)