bash - shell读写文件 - shell读取多行



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

我试图循环通过文本文件的目录,并将其合并成一个文件。 这很好,但文本文件包含代码片段,我所有的格式都被折叠到左边。 一行上的所有前导空白都被删除。

#!/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

我承认是一个bash noob,但经过高低寻找我找不到一个合适的解决方案。 显然,BASH总体上讨厌领先的白色空间。


正如其他人指出的那样,使用cat或者awk而不是read-echo循环是一个更好的方法 - 避免空白修剪问题(和其他一些你还没有偶然发现的问题),运行得更快,至少和猫一样,只是简单的代码。 尽管如此,我想刺激读取回声循环的正确工作。

首先是空白修剪问题:读命令自动修剪前后空白; 这可以通过将IFS变量设置为空来更改其空格的定义来解决。 此外,假设在行尾有一个反斜杠,意味着下一行是连续的,并且应该和这个连接在一起; 要解决这个问题,请使用-r(raw)标志。 这里的第三个问题是,echo的许多实现都在字符串中解释转义序列(例如,它们可能会把\ n变成一个实际的换行符)。 要解决这个问题,请使用printf来代替。 最后,就像一般的脚本卫生规则一样,当你不需要的时候,你不应该使用猫; 改用输入重定向。 随着这些变化,内部循环如下所示:

while IFS='' read -r line; do 
  printf "%s\n" "$line">>$OUTPUT
done <$f

...周围的脚本还有其他一些问题:试图将FILES定义为可用.textile文件列表的行已经引用了它,这意味着它永远不会被展开到实际的文件列表中。 最好的办法是使用一个数组:

FILES=(../best-practices/*.textile)
...
for f in "${FILES[@]}"

(如果任何文件名中有空格或其他有趣的字符,所有出现的$ 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

这是合并文件的过于昂贵的方式。

cat ../best-practices/*.textile >  ../best_practices.textile

如果要在连接时为每个文件添加空白(换行符),请使用awk

awk 'FNR==1{print "">"out.txt"}{print > "out.txt" }' *.textile

要么

awk 'FNR==1{print ""}{print}' file* > out.txt

代替:

cat $f | while read line; do 
    echo "$line">>$OUTPUT
done

做这个:

cat $f >>$OUTPUT

(如果有一个原因,你需要逐行处理,那么在问题中加入这个就好了)。


正确的答案是, 这是,转载如下:

while IFS= read line; do
    check=${line:0:1}
done < file.txt

请注意,它将处理从另一个命令输入输入的情况,而不仅仅是来自实际文件。

请注意,您还可以简化重定向,如下所示。

#!/bin/bash
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
  echo "Processing $f file..."
  {
  echo

  while IFS= read line; do 
      echo "$line"
  done < $f
  echo
  echo;
  } > $OUTPUT
done




cat