我有一个Bash脚本,我想在传递的参数中保留引号.
例:
./test.sh this is "some test"
Run Code Online (Sandbox Code Playgroud)
然后我想使用这些参数,并重用它们,包括整个参数列表的引号和引号.
我尝试使用\"$@\",但删除了列表中的引号.
我该如何做到这一点?
Chr*_*odd 82
using "$@"将把参数替换为列表,而不是在空格上重新拆分它们(它们在调用shell脚本时被拆分一次),如果你只想将参数重新传递给另一个程序,这通常就是你想要的.
你想做什么,以什么方式不工作?
unh*_*mer 39
只有当你是剧本的唯一用户时,Yuku的回答才有效,而如果你主要对打印字符串感兴趣,并且期望它们没有引号引用,那么Dennis Williamson是很好的.
如果您想将所有参数作为一个大的quoted-string参数传递给or 的-c参数,则可以使用以下版本:bashsu
#!/bin/bash
C=''
for i in "$@"; do
i="${i//\\/\\\\}"
C="$C \"${i//\"/\\\"}\""
done
bash -c "$C"
Run Code Online (Sandbox Code Playgroud)
所以,所有参数都会在它们周围引用一个引号(如果它之前不存在,则为无害),但是我们也会逃避任何转义,然后转义已经存在于参数中的任何引号(语法${var//from/to}执行全局子串替换) .
你当然只能引用已经有空格的东西,但这里没关系.像这样的脚本的一个实用程序是能够拥有一组预定义的环境变量(或者,使用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"
Run Code Online (Sandbox Code Playgroud)
我切换到''自弹也解释之类的东西$,并!!在""-quotes.
Pau*_*ce. 33
如果可以安全地假设包含空格的参数必须已经(并且应该)引用,那么您可以像这样添加它们:
#!/bin/bash
whitespace="[[:space:]]"
for i in "$@"
do
if [[ $i =~ $whitespace ]]
then
i=\"$i\"
fi
echo "$i"
done
Run Code Online (Sandbox Code Playgroud)
这是一个示例运行:
$ ./argtest abc def "ghi jkl" $'mno\tpqr' $'stu\nvwx'
abc
def
"ghi jkl"
"mno pqr"
"stu
vwx"
Run Code Online (Sandbox Code Playgroud)
您还可以使用- 和- - 在双引号或单引号内插入文字制表符和换行符,而不是在其中使用转义符.CtrlV TabCtrlV CtrlJ$'...'
关于在Bash中插入字符的注意事项:如果您在Bash中使用Vi键绑定(set -o vi)(Emacs是默认值 - set -o emacs),则需要处于插入模式才能插入字符.在Emacs模式下,您始终处于插入模式.
Tom*_*ale 25
有两种安全的方法可以做到这一点:
${variable@Q}:通过${variable@Q}以下方式扩展变量时:
扩展是一个字符串,它是以可以重用为输入的格式引用的参数值.
例:
$ expand-q() { for i; do echo ${i@Q}; done; } # Same as for `i in "$@"`...
$ expand-q word "two words" 'new
> line' "single'quote" 'double"quote'
word
'two words'
$'new\nline'
'single'\''quote'
'double"quote'
Run Code Online (Sandbox Code Playgroud)
printf %q "$quote-me"printf支持内部引用.该手册的入门printf说:
%q使printf以可以重用为shell输入的格式输出相应的参数.
例:
$ 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
$
Run Code Online (Sandbox Code Playgroud)
请注意,如果向人类显示引用文本,第二种方式会更清晰.
相关:对于bash,POSIX sh和zsh:使用单引号而不是反斜杠引用字符串
就像汤姆黑尔说的那样,一种方法是printf使用%q引用 - 逃避.
例如:
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}"
Run Code Online (Sandbox Code Playgroud)
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}"
Run Code Online (Sandbox Code Playgroud)
receiver.sh
#!/bin/bash
for arg in "$@"; do
echo "$arg"
done
Run Code Online (Sandbox Code Playgroud)
用法示例:
$ ./send_all_args.sh
$ ./send_all_args.sh a b
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 a b
b
$ ./send_fewer_args.sh "a' b" 'c "e '
c "e
$ ./send_fewer_args.sh "a' b" 'c "e ' 'f " g'
c "e
f " g
Run Code Online (Sandbox Code Playgroud)
我需要这个将所有参数转发给另一个解释器.最适合我的是:
bash -c "$(printf ' %q' "$@")"
Run Code Online (Sandbox Code Playgroud)
示例(当命名为forward.sh时):
$ ./forward.sh echo "3 4"
3 4
$ ./forward.sh bash -c "bash -c 'echo 3'"
3
Run Code Online (Sandbox Code Playgroud)
(当然我使用的实际脚本更复杂,涉及我的情况nohup和重定向等,但这是关键部分.)
将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.
Run Code Online (Sandbox Code Playgroud)
只需使用:
"${@}"
Run Code Online (Sandbox Code Playgroud)
例如:
# cat t2.sh
for I in "${@}"
do
echo "Param: $I"
done
# cat t1.sh
./t2.sh "${@}"
# ./t1.sh "This is a test" "This is another line" a b "and also c"
Param: This is a test
Param: This is another line
Param: a
Param: b
Param: and also c
Run Code Online (Sandbox Code Playgroud)
我的问题是相似的,并且我在这里使用了混合想法。
我们有一台带有PHP脚本的服务器,可以发送电子邮件。然后,我们有第二台服务器,它通过SSH连接到第一台服务器并执行它。
这两个服务器上的脚本名称相同,并且实际上都是通过bash脚本执行的。
在服务器1(本地)bash脚本上,我们只有:
/usr/bin/php /usr/local/myscript/myscript.php "$@"
Run Code Online (Sandbox Code Playgroud)
它位于/usr/local/bin/myscript远程服务器上,并由远程服务器调用。即使对于带有空格的参数,它也可以正常工作。
但是,在远程服务器上,我们不能使用相同的逻辑,因为第一台服务器将不会收到来自的报价"$@"。我使用JohnMudd和Dennis Williamson的想法来重新创建带引号的选项和参数数组。我喜欢仅在项目中有空格时才添加转义引号的想法。
因此,远程脚本运行:
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[@]}"
Run Code Online (Sandbox Code Playgroud)
请注意,我"${CSMOPTS[@]}"习惯将options数组传递给远程服务器。
感谢您在此处发布的eveyone!它真的帮助了我!:)
Ran*_*ku' -18
只需在字符串周围使用单引号和双引号即可:
./test.sh this is '"some test"'
Run Code Online (Sandbox Code Playgroud)
所以单引号里面的双引号也被解释为字符串。
但我建议将整个字符串放在单引号之间:
./test.sh 'this is "some test" '
Run Code Online (Sandbox Code Playgroud)
为了了解 shell 正在做什么或者解释脚本中的参数,您可以编写一个像这样的小脚本:
#!/bin/bash
echo $@
echo "$@"
Run Code Online (Sandbox Code Playgroud)
然后您将看到并测试使用不同字符串调用脚本时会发生什么