如何在IFS读取

时间:2017-04-18 22:58:42

标签: bash shell unix

我有一段时间的IFS读取循环来检查行中的不同匹配。

我检查并清空/空行如下:

while IFS= read -r line; do
[[ -z $line ]] && printf some stuff

我还想检查匹配的空/空是否也是文件的最后一行。我将在很多文件上运行这个脚本,它们都是:

- 以空行结尾

- 他们都是不同的长度所以我不能假设任何事情

- 他们有其他空行但不一定在最后(这就是为什么我必须区分) 提前谢谢。

1 个答案:

答案 0 :(得分:0)

正如chepner所指出的,在一个shell读取循环中,知道某一行是否是 last 的唯一方法是尝试读取 next one

您可以模仿"偷看"在下一行使用下面的代码,它允许您在仍然统一处理线条的同时检测所需的条件 这个解决方案可能不适合所有人,因为逻辑是非常重要的,因此需要相当多的额外的,非显而易见的代码,并且处理速度也会降低。

请注意,代码假定最后一行有一个尾随\n(因为所有结构良好的多行文本输入都应该有)。

#!/usr/bin/env bash

eof=0 peekedChar= hadEmptyLine=0 lastLine=0
while IFS= read -r line || { eof=1; (( hadEmptyLine )); }; do

  # Construct the 1-2 element array of lines to process in this iteration:
  #   - an empty line detected in the previous iteration by peeking, if applicable
  (( hadEmptyLine )) && aLines=( '' ) || aLines=()
  #   - the line read in this iteration, with the peeked char. prepended
  if (( eof )); then
    # No further line could be read in this iteration; we're here only because
    # $hadEmptyLine was set, which implies that the empty line we're processing
    # is by definition the last one.
    lastLine=1 hadEmptyLine=0
  else  
    # Add the just-read line, with the peeked char. prepended.
    aLines+=( "${peekedChar}${line}" )

    # "Peek" at the next line by reading 1 character, which 
    # we'll have to prepend to the *next* iteration's line, if applicable.
    # Being unable to read tells us that this is the last line.
    IFS= read -n 1 peekedChar || lastLine=1
    # If the next line happens to be empty, our "peeking" has fully consumed it,
    # so we must tell the next iteration to insert processing of this empty line.
    hadEmptyLine=$(( ! lastLine && ${#peekedChar} == 0 ))
  fi

  # Process the 1-2 lines.
  ndx=0 maxNdx=$(( ${#aLines[@]} - 1 ))
  for line in "${aLines[@]}"; do
    if [[ -z $line ]]; then # an empty line
      # Determine if this empty line is the last one overall.
      thisEmptyLineIsLastLine=$(( lastLine && ndx == maxNdx ))
      echo "empty line; last? $thisEmptyLineIsLastLine"
    else
      echo "nonempty line:    [$line]"
    fi
    ((++ndx))
  done

done < file