我有一个脚本,当直接调用时,可以使用以下参数组合正常工作:
--path=/path/to/a\ folder\ with\ spaces
--path='/path/to/a folder with spaces'
--path="/path/to/a folder with spaces"
但是我很难将辅助脚本中的参数传递给它。
我已经尝试了很多东西,但在每种情况下,就好像我的脚本收到以下内容:--path=/path/to/a folder with spaces
混淆了我的脚本,就好像/path/to/a
是路径(即--path的参数)和folder
with
spaces
是额外的参数。
作为一个最小的例子,以下所有内容都不会产生所需的结果(将下面的内容保存为./so_example.sh
和chmod +x ./so_example.sh
所需的工作目录):
#!/usr/bin/env bash
set -x
printf "%s\n" "$@"
echo "$@"
echo -e "$@"
printf "%s\n" $@
echo $@
echo -e $@
在以下每种方式中调用它时:
./so_example.sh --path=/path/to/a\ folder\ with\ spaces
./so_example.sh --path='/path/to/a folder with spaces'
./so_example.sh --path="/path/to/a folder with spaces"
我得到以下输出:
+ printf '%s\n' '--path=/path/to/a folder with spaces'
--path=/path/to/a folder with spaces
+ echo '--path=/path/to/a folder with spaces'
--path=/path/to/a folder with spaces
+ echo -e '--path=/path/to/a folder with spaces'
--path=/path/to/a folder with spaces
+ printf '%s\n' --path=/path/to/a folder with spaces
--path=/path/to/a
folder
with
spaces
+ echo --path=/path/to/a folder with spaces
--path=/path/to/a folder with spaces
+ echo -e --path=/path/to/a folder with spaces
--path=/path/to/a folder with spaces
我希望获得以下输出之一以获得正确的解决方案:
--path=/path/to/a\ folder\ with\ spaces`
--path='/path/to/a folder with spaces'`
--path="/path/to/a folder with spaces"`
问题是你希望语法引号传递给你的脚本;他们不是。全部三个
--path=/path/to/a\ folder\ with\ spaces
--path='/path/to/a folder with spaces'
--path="/path/to/a folder with spaces"
由调用者计算以生成参数的完全相同的值(--path=/path/to/a folder with spaces
)。在脚本中引用位置参数可以保留这些空间,但是您的脚本无法知道调用它的人是如何创建该值的。 (它可能是以你的脚本一无所知的方式创建的;考虑从dash -c 'printf "%s\n" "$1"' _ $'\t'
运行的bash
这样的命令.dash
获取单个制表符作为其参数,但它不知道用于创建的$'...'
语法bash
的任何信息它。)
你必须在单个处理中明确使用“$ 1”或迭代“$ @”。如果您需要在单个var中保留“$ @”的空格,请使用字符串操作来屏蔽不间断的空格。
以下示例将与--path =“PATTERN”和--path“PATTERN”一起使用。它从“$ @”中删除所有路径并将其移动到单个var $路径中(如果“$ @”包含您要保留的其他参数)
# remove options from positional parameters and read arguments
i=1
while [ $i -le $# ]
do
case "$1" in
--path=*)
test -a "$1"
if [ $? != 0 ]
then
# allow nontrivial names in --path=PATTERN
# (space, tab, newline, linefeed, formfeed, vertical tab)
paths="${paths} ${1//[[:space:]]/[[:space:]]}"
i=$(($i-1))
else
set -- "$@" "$1"
fi
;;
--path)
test -a "$1"
if [ $? != 0 ]
then
# allow nontrivial names in --path PATTERN
# (space, tab, newline, linefeed, formfeed, vertical tab)
paths="${paths} $1=${2//[[:space:]]/[[:space:]]}"
shift
i=$(($i-1))
else
set -- "$@" "$1"
fi
;;
*)
set -- "$@" "$1"
;;
esac
shift
i=$(($i+1))
done
# you can now pass the arguments to your command. the [[:space:]] will
# recognized as wildcard and will match all names containing spaces
<command> $paths
# however, if you want to display names (or if these paths not exist),
# you can convert it back (only spaces unfortunately)
for path in $paths
do
# revert back replacements [[:space:]] -> ' '
path="${path//\[\[:space:]]/ }"
# print everything before separator: ${VAR%%=*}
# print the separator: (=)
# print double quote: (\")
# print everything after separator: ${VAR#*=}
# print double quote: (\")
# echo -e " ${path%%=*} = \" ${path#*=} \" "
echo -e "${path%%=*}=\"${path#*=}\""
done
# other arguments are still available in positional parameters
for rest in "$@"
do
echo -e $rest
done