在shell中构建实用程序参数的便携式方法?

9
我正在编写一个shell脚本,旨在在一系列机器上运行。其中一些机器具有bash 2或bash 3。有些正在运行BusyBox 1.18.4,其中bin/bash存在,但是:
  • /bin/bash --version根本没有返回任何内容
  • foo=("hello" "world")会抱怨语法错误,附近意外的"(",无论是否在括号内部加入额外的空格...所以数组似乎要么有限制要么缺失

还有更现代或功能更完整的Linux和bash版本。

对于一个bash脚本,在运行时为调用某个实用程序(如find)建立参数的最便携方式是什么?我可以构建一个字符串,但感觉数组可能是更好的选择。除了上面的第二个要点...

假设我的脚本是foo,您这样调用它:foo -o 1 .jpg .png

以下是一些伪代码:

#!/bin/bash

# handle option -o here
shift $(expr $OPTIND - 1)

# build up parameters for find here
parameters=(my-diretory -type f -maxdepth 2)
if [ -n "$1" ]; then
    parameters+=-iname '*$1' -print
    shift
fi

while [ $# -gt 0 ]; do
    parameters+=-o -iname '*$1' -print
    shift
done

find <new positional parameters here> | some-while-loop
2个回答

7

如果您需要使用大多数POSIX sh(例如在busybox ash-named-bash中可用),则可以直接使用set构建位置参数。

$ set -- hello
$ set -- "$@" world
$ printf '%s\n' "$@"
hello
world

为了更恰当的举例说明:
$ set -- /etc -name '*b*'
$ set -- "$@" -type l -exec readlink {} +
$ find "$@"
/proc/mounts

如果我在脚本中使用 set --,那么原来传入的参数会被丢弃吗?我正在使用这些参数构建 find 命令的参数... - user1011471
当您传递位置参数时,它们将在"$@"变量中可用。因此,如果您想添加更多的位置参数,您必须执行类似于set -- "$@" --more --more --more的操作。明白了吗? - kojiro
哦。我想做的是将我的脚本位置参数转换为find的内容,然后调用find。但是这里"$@"被同时使用了... - user1011471
@user1011471 在你的问题中给出一个例子,我就能提供更多帮助。例如,在已知的操作系统上展示它在现代 bash 中的工作方式,并寻求帮助使其在 POSIX sh 中运行。 - kojiro
@user1011471,你可以把 set -- 放在一个函数内部,这样它只会丢弃函数的参数,而不是整个脚本的参数集合。 - Charles Duffy
或者我可以 set -- "$@" 一些神奇的值,然后进行处理和移位,直到我到达它。再移动一次,这就是传递给 find 的内容。 - user1011471

2

虽然您的问题不仅涉及Bash,但您可能会从阅读Wooledge Bash FAQ中获益:

http://mywiki.wooledge.org/BashFAQ/050

它提到了对于旧版本的shell可以使用“set --”,但也提供了很多背景信息。在构建参数列表时,很容易创建适用于简单情况但在数据具有特殊字符时失败的系统,因此阅读相关主题的信息可能是值得的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接