bash 标志,可选择从标准输入或文件中读取

bash flags with optional read from stdin or file

我知道这可能是一个愚蠢的问题,但它让我难住了。 我正在尝试编写一个接受标志和一个可选变量的 shell 脚本。一份文件。如果传递了文件,它会从文件中读取。如果不是,它从标准输入读取。我知道有人问过类似的问题,但我找不到我的具体问题的答案。

我在下面提供了一个示例来说明这个问题。为了简洁起见,我省略了一些部分(例如验证)。

我可以接受标志并从文件中读取。或者我可以选择接受一个变量(文件)并从文件中读取。如果没有传递文件,那么我们从标准输入读取。出于某种原因,当我尝试将两者结合使用时(接受标志,读取默认为标准输入的可选文件)我收到错误消息。

这有效。

#!/bin/sh
set -eu

while IFS=, read -r f1 
do
  echo $f1
done <"${1:-/dev/stdin}"

我可以这样称呼它... ./test.sh <<< "testing123" 或者这个... echo "testing123" | ./test.sh 或者这个... ./test.sh foo.csv。 所有 return testing123 假设 foo.csv 包含 testing123.

这也有效。

#!/bin/sh
set -eu

while true
do
  case  in
    -h|--help)
      echo "-h"
      exit
      ;;
    --)
      shift
      break
      ;;
    -?*)
      echo "unknown"
      ;;
    *)
      break
  esac

  shift
done

while IFS=, read -r f1 
do
  echo $f1
done <""

我可以这样称呼它 ./test.sh foo.csv 或这样 ./test.sh -f foo.csv。第一种情况returnstesting123和第二种情况returns

unknown
testing123

出于某种原因,这不起作用。我不明白我在这里错过了什么?

#!/bin/sh
set -eu

while true
do
  case  in
    -h|--help)
      echo "-h"
      exit
      ;;
    --)
      shift
      break
      ;;
    -?*)
      echo "unknown"
      ;;
    *)
      break
  esac

  shift
done

while IFS=, read -r f1 
do
  echo $f1
done <"${1:-/dev/stdin}"

这样调用 ./test foo.csv 它 returns testing123。 像这样调用 ./test -f foo.csv 它 returns

unknown
testing123

这样调用:

echo "testing123" | ./test.sh

或这个

./test.sh <<< "testing123"

它returns

./test.sh: line 6:  unbound variable

改变

while true

while [ $# -ne 0 ]

当您 运行 没有参数时,您的代码将继续循环的下一次迭代,并尝试测试不存在的 </code>。由于您已完成 <code>set -eu,引用未设置的变量会导致错误并且脚本中止。