Bash:如何在引用中保留引号?
我有一个Bash脚本,我想在传递的参数中保留引号。
例:
./test.sh this is "some test"
那么我想使用这些参数,并重新使用它们,包括整个参数列表中的引号和引号。
我尝试使用\"$@\"
,但删除列表中的引号。
我如何做到这一点?
./test.sh this is '"some test"'
使用"$@"
会将参数replace为一个列表,而不用将它们重新分割成空格(当shell脚本被调用时它们被分割一次),这通常正是你想要的,如果你只是想重新传递参数到另一个程序。
你想做什么,以什么方式不工作?
Yuku的答案只适用于如果你是剧本的唯一使用者,而Dennis Williamson则是非常棒的,如果你主要想打印string,并且期望他们没有引号。
如果你想把所有的参数作为一个大引用stringparameter passing给bash
或者su
的-c
参数,那么这个版本是可以使用的:
#!/bin/bash C='' for i in "$@"; do i="${i//\\/\\\\}" C="$C \"${i//\"/\\\"}\"" done bash -c "$C"
所以, 所有的参数都会得到一个引号(为了这个目的,前面没有这个参数是无害的),但是我们也逃脱了任何转义,然后转义已经在参数中的引号(语法${var//from/to}
做全局子串replace)。
你当然可以只引用已经有空白的东西,但在这里没关系。 像这样的脚本的一个实用工具是能够有一个预定义的一组环境variables(或者,用su作为特定的用户运行的东西,而不是双重引用所有的东西)。
更新:我最近有理由以最小的分叉POSIX的方式做到这一点,导致这个脚本(最后一个printf那里输出的命令行用来调用脚本,你应该能够复制粘贴为了调用它与等价的参数):
#!/bin/sh C='' for i in "$@"; do case "$i" in *\'*) i=`printf "%s" "$i" | sed "s/'/'\"'\"'/g"` ;; *) : ;; esac C="$C '$i'" done printf "$0%s\n" "$C"
我切换到''
因为壳也解释的东西像$
和!!
在""
引用。
如果假设一个包含空格的参数一定是(而且应该)被引用是安全的,那么你可以像这样来添加它们:
#!/bin/bash whitespace="[[:space:]]" for i in "$@" do if [[ $i =~ $whitespace ]] then i=\"$i\" fi echo "$i" done
这是一个示例运行:
$ ./argtest abc def "ghi jkl" $'mno\tpqr' $'stu\nvwx' abc def "ghi jkl" "mno pqr" "stu vwx"
您还可以在双引号或单引号内使用Ctrl – V Tab和Ctrl – V Ctrl – J 插入文字标签和换行符,而不是使用$'...'
内的转义符。
有关在Bash中插入字符的注意事项:如果您在Bash中使用Vi键绑定( set -o vi
)(Emacs是默认set -o emacs
),则需要处于插入模式才能插入字符 。 在Emacs模式下,您始终处于插入模式。
bash
支持在内部引用。 该手册的printf
条目说:
%q
导致printf以可以重新用作shellinput的格式输出相应的参数。
例:
$ cat test.sh #!/bin/bash printf "%q\n" "$@" $ $ ./test.sh this is "some test" 'new >line' "single'quote" 'double"quote' this is some\ test $'new\nline' single\'quote double\"quote $
瞧。
改变unhammer的例子使用数组。
printargs() { printf "'%s' " "$@"; echo; }; # http://superuser.com/a/361133/126847 C=() for i in "$@"; do C+=("$i") # Need quotes here to append as a single array element. done printargs "${C[@]}" # Pass array to a program as a list of arguments.
引号由bash解释,并不存储在命令行参数或variables值中。
如果您想使用引用的参数,则必须在每次使用引用时引用它们:
val="$3" echo "Hello World" > "$val"
我的问题是相似的,我用这里张贴的混合想法。
我们有一个PHP脚本的服务器发送电子邮件。 然后我们有第二台服务器通过SSH连接到第一台服务器并执行它。
两个服务器上的脚本名称是相同的,而且两者实际上都是通过bash脚本执行的。
在服务器1(本地)bash脚本我们只是:
/usr/bin/php /usr/local/myscript/myscript.php "$@"
这位于/usr/local/bin/myscript
,由远程服务器调用。 即使有空格的参数也可以正常工作。
但是在远程服务器上,我们不能使用相同的逻辑,因为第一台服务器不会收到"$@"
的引号。 我使用JohnMudd和Dennis Williamson的想法来重新创build带引号的选项和参数数组。 只有当物品中有空格时,我才喜欢添加转义引号。
所以远程脚本运行:
CSMOPTS=() whitespace="[[:space:]]" for i in "$@" do if [[ $i =~ $whitespace ]] then CSMOPTS+=(\"$i\") else CSMOPTS+=($i) fi done /usr/bin/ssh "$USER@$SERVER" "/usr/local/bin/myscript ${CSMOPTS[@]}"
请注意,我使用"${CSMOPTS[@]}"
将选项数组传递给远程服务器。
感谢eveyone发布在这里! 这真的帮助我! 🙂
就像Tom Hale所说的那样,使用%q
来引用escape的方法就是printf
。
例如:
send_all_args.sh
#!/bin/bash if [ "$#" -lt 1 ]; then quoted_args="" else quoted_args="$(printf " %q" "${@}")" fi bash -c "$( dirname "${BASH_SOURCE[0]}" )/receiver.sh${quoted_args}"
send_fewer_args.sh
#!/bin/bash if [ "$#" -lt 2 ]; then quoted_last_args="" else quoted_last_args="$(printf " %q" "${@:2}")" fi bash -c "$( dirname "${BASH_SOURCE[0]}" )/receiver.sh${quoted_last_args}"
receiver.sh
#!/bin/bash for arg in "$@"; do echo "$arg" done
用法示例:
$ ./send_all_args.sh $ ./send_all_args.sh ab a b $ ./send_all_args.sh "a' b" 'c "e ' a' b c "e $ ./send_fewer_args.sh $ ./send_fewer_args.sh a $ ./send_fewer_args.sh ab b $ ./send_fewer_args.sh "a' b" 'c "e ' c "e $ ./send_fewer_args.sh "a' b" 'c "e ' 'f " g' c "ef " g