带Bash的文件逐行读取

时间:2018-11-19 19:35:36

标签: bash unix while-loop line-by-line

我正在创建一个bash脚本来逐行读取文件,该文件后来被格式化以按名称和日期进行组织。即使我已经尝试使用目录查找器和导出命令自行对输入和输出文件名变量进行了尝试,我也看不到为什么这段代码现在无法正常工作。

export inputfilename="employees.txt"
export outputfilename="branch.txt"
directoryinput=$(find -name $inputfilename)
directoryoutput=$(find -name $outputfilename)
n=1

if [[ -f "$directoryinput" ]]; then
     while read line; do
         echo "$line"
         n=$((n+1))
     done < "$directoryoutput"
 else
    echo "Input file does not exist. Please create a employees.txt file"
 fi

非常感谢所有帮助,谢谢! 注意:正如人们注意到的那样,我忘了在数据传输到文件中添加$符号,但这只是在复制代码时,我的实际应用程序中确实有$符号,但仍然没有结果

1 个答案:

答案 0 :(得分:1)

  

用Bash逐行读取文件

逐行读取文件的最佳方式是:

while IFS= read -r line; do
  // parse line
  printf "%s" "$line"
done < "file"

有关该主题的更多信息,请访问bashfaq

但是,不要逐行读取bash中的文件。您可以(几乎可以)始终不以bash逐行读取流。用bash逐行读取文件非常慢,因此不应该这样做。对于简单的情况,可以使用借助xargsparallel的所有unix工具,对于更复杂的awkdatamesh,则可以使用。

  

done < "directoryoutput"

代码不起作用,因为您正在传递while读取循环作为标准输入,名为directoryoutput的文件的输入。由于此类文件不存在,因此脚本将失败。

  

directoryoutput=$(find -name $outputfilename)

只需使用HERE字符串构造将变量值加上换行符附加到read while循环中即可:

done <<< "$directoryoutput"

  

directoryinput=$(find -name $inputfilename)
  if [[ -f "$directoryinput" ]]

这可以,只要您的目录中只有一个名为$inputfilename的文件即可。同样,查找文件然后检查其是否存在也没有意义。如果文件更多,请查找以换行符分隔的名称列表。不过,我认为可以使用小额支票if [ "$(printf "$directoryinput" | wc -l)" -eq 1 ]或使用find -name $inputfilename | head -n1

while read line;
   do
      echo "$line"
      n=$((n+1))
  done < "directoryoutput"

这里的意图很明确。就是这样:

 n=$(<directoryoutput wc -l)
 cat "directoryoutput"

除了while read line删除了结尾的换行符和前导的换行符,并且依赖于IFS。

除非您有理由不这么做,否则请始终记得引用变量。

看看shellcheck,它可以发现脚本中最常见的错误。

我会这样做:

inputfilename="employees.txt"
outputfilename="branch.txt"

directoryinput=$(find . -name "$inputfilename")
directoryinput_cnt=$(printf "%s\n" "$directoryinput" | wc -l)
if [ "$directoryinput_cnt" -eq 0 ]; then
   echo "Input file does not exist. Please create a '$inputfilename' file" >&2
   exit 1
elif [ "$directoryinput_cnt" -gt 1 ]; then
   echo "Multiple file named '$inputfilename' exists in the current path" >&2
   exit 1
fi

directoryoutput=$(find . -name "$outputfilename")
directoryoutput_cnt=$(printf "%s\n" "$directoryoutput" | wc -l)

if [ "$directoryoutput_cnt" -eq 0 ]; then 
    echo "Input file does not exist. Please create a '$outputfilename' file" >&2
    exit 1
elif [ "$directoryoutput_cnt" -gt 1 ]; then 
   echo "Multiple file named '$outputfilename' exists in the current path" >&2
    exit 1
fi

cat "$directoryoutput"
n=$(<"$directoryoutput" wc -l)