所以,如果设置了--xyz
标志,我有一个需要运行X的bash脚本,否则为Y.它还需要将所有命令行参数传递给它运行的程序。我的问题在于,我不能让它完全按照它们出现的方式传递参数,而是要么逃避不需要转义的东西,要么剥离应该转义的东西的转义。
这是我的测试脚本:
#!/bin/sh
echo "$@"
args=$@
BASEDIR=$(dirname $0)
while test $# -gt 0
do
case "$1" in
--xyz) echo ${args/--xyz/}
exit $?
;;
esac
shift
done
echo "$args"
printf %s "$args"
echo
echo "$(printf %s "$args")"
echo "$(printf %q "$args")"
然后我这样测试:
[jearls@earlzpremb X]$ ./test.sh -c Foo\ Bar
-c Foo Bar
-c Foo Bar
-c Foo Bar
-c Foo Bar
-c\ Foo\ Bar
[jearls@earlzpremb X]$ echo -c Foo\ Bar
-c Foo Bar
[jearls@earlzpremb X]$ echo "-c Foo\ Bar"
-c Foo\ Bar
我需要它像最后一个命令。 Foo \ Bar保留了空间的逃逸,但是在-c之后没有逃离空间。
我无法控制传递给此脚本的参数,因此我无法进行双重转义或类似的操作。
我怎样才能达到传递命令行参数的目标,基本上是逐字逐句地转义到另一个程序?
答案 0 :(得分:4)
您可以(轻松地)将参数 list 转换为字符串,使其可以转换回列表。幸运的是,你很少需要这样做。
我不清楚你的要求是什么,但这是一个简单的脚本,它似乎展示了你期望的行为:
# Function to execute if --xyz in argument list
X() { local -i i=0
for arg in "$@"; do echo X$((++i)): "$arg"; done
}
# Function to call otherwise
Y() { local -i i=0
for arg in "$@"; do echo Y$((++i)): "$arg"; done
}
# Select one or the other
x_or_y() {
local arg
# Scan arguments for --xyz (Not very precise)
for arg in "$@"; do
case "$arg" in
--xyz) X "$@";
return $?;;
--) break;;
esac
done
# No --xyz found
Y "$@"
}
# Demonstrate that arguments are passed verbatim:
$ x_or_y something "a b c" 'a backslash\inside'
Y1: something
Y2: a b c
Y3: a backslash\inside
$ x_or_y something --xyz "a b c" 'a backslash\inside'
X1: something
X2: --xyz
X3: a b c
X4: a backslash\inside
使用bash,如果需要删除--xyz
参数,则可以使用数组。 (你也可以使用set --
,但我认为数组更清晰了):
x_or_y() {
local -i i=1
local arg
local todo=Y
local args=()
# Scan arguments for --xyz (Not very precise)
for arg in "$@"; do
((++i))
case "$arg" in
--xyz) todo=X; break;;
--) args+=("$arg"); break;;
*) args+=("$arg");;
esac
done
# Call with the args scanned and the rest of the args:
"$todo" "${args[@]}" "${@:i}"
}
编辑:正如Etan Reisner所说,没有数组就可以做到这一点。该数组是一种有用的技术,但对于这个问题,您可以使用子字符串表达式来实现:
x_or_y() {
local -i i
local -i skip=0
local todo=Y
# Scan arguments for --xyz (Not very precise)
for ((i=1; i<=$#; ++i)); do
case "${!i}" in
--xyz) todo=X; skip=1; break;;
--) break;;
esac
done
# Call with the args scanned and the rest of the args:
"$todo" "${@:1:i-1}" "${@:i+skip}"
}
答案 1 :(得分:1)
如果您需要从参数列表中删除--xyz
参数,则以下内容应该有效(尽管我不知道这是否适用于/bin/sh
)。
$ cat test.sh
#!/bin/sh
c() {
printf 'argc: %s\n' "$#";
printf 'argv: %s\n' "$@"
}
counter=1
for arg; do
case $arg in
--xyz)
echo "Found $arg at position $counter"
break
;;
esac
((counter++))
done
echo "${@::$counter}" "${@:$((counter + 1))}"
c "${@::$counter}" "${@:$((counter + 1))}"
$ ./test -c Foo\ Bar -a Blah\ Quux
-c Foo Bar -a Blah Quux
argc: 4
argv: -c
argv: Foo Bar
argv: -a
argv: Blah Quux
$ ./test.sh -c Foo\ Bar --xyz -a Blah\ Quux
Found --xyz at position 3
-c Foo Bar -a Blah Quux
argc: 4
argv: -c
argv: Foo Bar
argv: -a
argv: Blah Quux