bash - 我如何在 Bash 中解析命令行参数?

标签 bash command-line scripting arguments getopts

比如说,我有一个用这一行调用的脚本:

./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile

或者这个:

./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 

在每种情况下(或两者的某种组合)$v$f$d<,可接受的解析方式是什么 将全部设置为 true 并且 $outFile 将等于 /fizz/someOtherFile?

最佳答案

Bash 空格分隔(例如 --option argument )

cat >/tmp/demo-space-separated.sh <<'EOF'
#!/bin/bash

POSITIONAL_ARGS=()

while [[ $# -gt 0 ]]; do
  case $1 in
    -e|--extension)
      EXTENSION="$2"
      shift # past argument
      shift # past value
      ;;
    -s|--searchpath)
      SEARCHPATH="$2"
      shift # past argument
      shift # past value
      ;;
    --default)
      DEFAULT=YES
      shift # past argument
      ;;
    -*|--*)
      echo "Unknown option $1"
      exit 1
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
done

set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)

if [[ -n $1 ]]; then
    echo "Last line of file specified as non-opt/last argument:"
    tail -1 "$1"
fi
EOF

chmod +x /tmp/demo-space-separated.sh

/tmp/demo-space-separated.sh -e conf -s /etc /etc/hosts
复制粘贴上面 block 的输出
FILE EXTENSION  = conf
SEARCH PATH     = /etc
DEFAULT         =
Number files in SEARCH PATH with EXTENSION: 14
Last line of file specified as non-opt/last argument:
#93.184.216.34    example.com
用法
demo-space-separated.sh -e conf -s /etc /etc/hosts

Bash 等号分隔(例如,--option=argument)

cat >/tmp/demo-equals-separated.sh <<'EOF'
#!/bin/bash

for i in "$@"; do
  case $i in
    -e=*|--extension=*)
      EXTENSION="${i#*=}"
      shift # past argument=value
      ;;
    -s=*|--searchpath=*)
      SEARCHPATH="${i#*=}"
      shift # past argument=value
      ;;
    --default)
      DEFAULT=YES
      shift # past argument with no value
      ;;
    -*|--*)
      echo "Unknown option $i"
      exit 1
      ;;
    *)
      ;;
  esac
done

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)

if [[ -n $1 ]]; then
    echo "Last line of file specified as non-opt/last argument:"
    tail -1 $1
fi
EOF

chmod +x /tmp/demo-equals-separated.sh

/tmp/demo-equals-separated.sh -e=conf -s=/etc /etc/hosts
复制粘贴上面 block 的输出
FILE EXTENSION  = conf
SEARCH PATH     = /etc
DEFAULT         =
Number files in SEARCH PATH with EXTENSION: 14
Last line of file specified as non-opt/last argument:
#93.184.216.34    example.com
用法
demo-equals-separated.sh -e=conf -s=/etc /etc/hosts

更好地理解${i#*=}this guide 中搜索“删除子字符串” .它在功能上等同于 `sed 's/[^=]*=//' <<< "$i"`调用不必要的子进程或 `echo "$i" | sed 's/[^=]*=//'`这会调用两个 不必要的子进程。


将 bash 与 getopt[s] 一起使用

getopt(1) 限制(旧的,相对较新的 getopt 版本):

  • 不能处理空字符串参数
  • 无法处理带有嵌入空格的参数

最近getopt版本没有这些限制。有关详细信息,请参阅这些 docs .


POSIX 获取选项

此外,POSIX shell 和其他提供 getopts没有这些限制。我包括了一个简单的 getopts示例。

cat >/tmp/demo-getopts.sh <<'EOF'
#!/bin/sh

# A POSIX variable
OPTIND=1         # Reset in case getopts has been used previously in the shell.

# Initialize our own variables:
output_file=""
verbose=0

while getopts "h?vf:" opt; do
  case "$opt" in
    h|\?)
      show_help
      exit 0
      ;;
    v)  verbose=1
      ;;
    f)  output_file=$OPTARG
      ;;
  esac
done

shift $((OPTIND-1))

[ "${1:-}" = "--" ] && shift

echo "verbose=$verbose, output_file='$output_file', Leftovers: $@"
EOF

chmod +x /tmp/demo-getopts.sh

/tmp/demo-getopts.sh -vf /etc/hosts foo bar
复制粘贴上面 block 的输出
verbose=1, output_file='/etc/hosts', Leftovers: foo bar
用法
demo-getopts.sh -vf /etc/hosts foo bar

getopts的优点|是:

  1. 它更便携,并且可以在其他 shell 中工作,例如 dash .
  2. 它可以处理多个单个选项,例如 -vf filename以典型的 Unix 方式自动进行。

getopts的缺点是它只能处理短选项( -h ,而不是 --help )而无需额外的代码。

有一个getopts tutorial这解释了所有语法和变量的含义。在 bash 中,还有 help getopts ,这可能会提供信息。

关于bash - 我如何在 Bash 中解析命令行参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/192249/

相关文章:

c - 我需要在 c 中使用 getopt 将目录作为命令行参数获取

c++ - 如何在我的游戏中执行脚本?

linux - shell脚本看不到远程目录中的文件

bash - 如何在 bash 中发生匹配之前忽略所有行?

java - 命令行中的引号

Shell 脚本和 md5/md5sum 命令 : need to decide when to use which one

scripting - CAPL 是脚本语言还是编程语言?

用于查找文件名中特定单词的 linux 脚本

python - 使用参数从 python 执行 Shell 脚本

linux - git 和 mvn 命令在 mac/Linux 中去哪里?