linux - 在 Bash(和其他 shell 语言)中,如何在传递的参数中保留空格转义字符
问题描述
我有一个脚本,当直接调用它时,它可以与以下参数组合正常工作:
--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"`
解决方案
您必须在单个处理中显式使用“$1”或迭代“$@”。如果您需要在单个 var 中保留 "$@" 的空格,请使用字符串操作来使用不间断空格进行掩码。
以下示例将使用 --path="PATTERN" 和 --path "PATTERN"。它从 "$@" 中删除所有路径并将其移动到单个 var $paths 中(以防 "$@" 包含您要保留的其他参数)
# 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
推荐阅读
- c# - Unity 错误 CS0246(找不到命名空间)
- assemblyscript - AssemblyScript 中的 TypedArray 与 Array
- mocking - 在 Jest 中模拟具有进行 Axios 调用的函数的对象
- ruby - 在 Ruby 中查找第二长的数组 - Collatz 猜想算法
- php - 如何使用 php 在 excelsheet 上重复输出
- php - PHP-在多维数组中搜索键
- kubernetes - Spring Cloud Dataflow Kubernetes - 流外部 IP
- reactjs - 为什么我可以 console.log 值但不能 setState?
- python - Django 2.2 静态/媒体文件未显示/处理
- javascript - highcharts 中一张图表上的多个时间线