bash 函数参数奇怪的行为

bash 函数参数奇怪的行为

我有以下 bash 函数:

lscf() {
  while getopts f:d: opt ; do
    case $opt in
      f) file="$OPTARG" ;;
      d) days="$OPTARG" ;;
    esac
  done

  echo file is $file
  echo days is $days
}

使用参数运行此命令不会输出任何值。只有在不带参数运行该函数,然后再次使用参数运行该函数后,它才会输出正确的值:

-bash-4.1$ lscf -d 10 -f file.txt
file is
days is

-bash-4.1$ lscf
file is
days is

-bash-4.1$ lscf -d 10 -f file.txt
file is file.txt
days is 10

我错过了什么吗?

答案1

虽然我无法重现您问题中函数的初始运行,但您应该OPTIND在函数中重置为 1,以便能够在重复调用函数时处理函数的命令行。

bash手册:

OPTIND每次调用 shell 或 shell 脚本时都会初始化为 1。当选项需要参数时,getopts将该参数放入变量 中OPTARG外壳不会OPTIND 自动重置;getopts如果要使用一组新参数,则必须在同一 shell 调用中的多次调用之间手动重置它。

POSIX 标准:

如果应用程序设置OPTIND为值 1,则可以使用一组新参数:当前位置参数或新的 arg 值。getopts任何其他尝试在单个 shell 执行环境中使用在所有调用中都不相同的参数(位置参数或 arg 操作数)或将OPTIND值修改为 1 以外的值来多次调用,都会产生未指定的结果。

手册中提到的“shell 调用”bash与 POSIX 文本中提到的“单执行环境”相同,都是指您的 shell 脚本或交互式 shell。在脚本或交互式 shell 中,对您的多次调用将在同一环境中lscf调用,并且需要在每次此类调用之前重置为 1。getoptsOPTIND

所以:

lscf() {
  OPTIND=1

  while getopts f:d: opt ; do
    case $opt in
      f) file="$OPTARG" ;;
      d) days="$OPTARG" ;;
    esac
  done

  echo file is $file
  echo days is $days
}

如果变量filedays应该不是在调用 shell 的环境中设置,它们应该是局部变量。另外,引用变量扩展并用于printf输出变量数据:

lscf() {
  local file
  local days

  OPTIND=1

  while getopts f:d: opt ; do
    case $opt in
      f) file="$OPTARG" ;;
      d) days="$OPTARG" ;;
    esac
  done

  printf 'file is %s\n' "$file"
  printf 'days is %s\n' "$days"
}

相关内容