我有一个复杂的命令,我想做一个shell/bash脚本。我可以很容易地用1美元表示

foo $1 args -o $1.ext

我希望能够向脚本传递多个输入名称。正确的做法是什么?

当然,我想要处理包含空格的文件名。


当前回答

在脚本中使用命令格式化任何命令行选项或 参数。

#!/bin/bash
# Extract command line options & values with getopt
#
set -- $(getopt -q ab:cd "$@")
#
echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift

其他回答

放大baz的回答,如果您需要用索引枚举参数列表(例如搜索特定的单词),您可以在不复制列表或更改列表的情况下完成此操作。

假设你想用双破折号("——")分割一个参数列表,并将破折号之前的参数传递给一个命令,将破折号之后的参数传递给另一个命令:

 toolwrapper() {
   for i in $(seq 1 $#); do
     [[ "${!i}" == "--" ]] && break
   done || return $? # returns error status if we don't "break"

   echo "dashes at $i"
   echo "Before dashes: ${@:1:i-1}"
   echo "After dashes: ${@:i+1:$#}"
 }

结果应该是这样的:

 $ toolwrapper args for first tool -- and these are for the second
 dashes at 5
 Before dashes: args for first tool
 After dashes: and these are for the second

您还可以将它们作为数组元素访问,例如,如果您不想遍历所有这些元素

argc=$#
argv=("$@")

for (( j=0; j<argc; j++ )); do
    echo "${argv[j]}"
done
aparse() {
while [[ $# > 0 ]] ; do
  case "$1" in
    --arg1)
      varg1=${2}
      shift
      ;;
    --arg2)
      varg2=true
      ;;
  esac
  shift
done
}

aparse "$@"

对于简单的情况,你也可以使用shift。 它将参数列表视为队列。每次移位都会抛出第一个参数 其余每个参数的索引都递减。

#this prints all arguments
while test $# -gt 0
do
    echo "$1"
    shift
done

请注意,Robert的答案是正确的,它也适用于sh。你可以(可移植地)进一步简化它:

for i in "$@"

等价于:

for i

也就是说,你什么都不需要!

测试($ is命令提示符):

$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d

我第一次读到这个是Kernighan和Pike写的Unix Programming Environment。

在bash中,帮助文档如下:

对于名字[用语言来说…]do COMMANDS;完成 如果'in WORDS…;'不存在,则假定'in "$@"'。