首页 > 解决方案 > 可选从标准输入或文件读取的 bash 标志

问题描述

我知道这可能是一个愚蠢的问题,但它让我难住了。我正在尝试编写一个接受标志和一个可选变量的 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.csvtesting123假设 foo.csv 包含所有返回testing123

这也有效。

#!/bin/sh
set -eu

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

  shift
done

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

我可以这样./test.sh foo.csv或这样称呼它./test.sh -f foo.csv。第一种情况返回testing123,第二种情况返回

unknown
testing123

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

#!/bin/sh
set -eu

while true
do
  case $1 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它返回testing123。像这样调用./test -f foo.csv它返回

unknown
testing123

像这样调用:

echo "testing123" | ./test.sh

或这个

./test.sh <<< "testing123"

它返回

./test.sh: line 6: $1 unbound variable

标签: linuxbashshelloptional-parameters

解决方案


改变

while true

while [ $# -ne 0 ]

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


推荐阅读