如何在 Bash 参数中保留引号?
我有一个 Bash 脚本,我想在传递的参数中保留引号。
示例:
./test.sh this is "some test"
然后我想使用这些参数,并重用它们,包括引号和整个参数列表周围的引号。
我尝试使用 \"$@\"
,但这会删除列表中的引号。
我该如何实现这个目标?
I have a Bash script where I want to keep quotes in the arguments passed.
Example:
./test.sh this is "some test"
Then I want to use those arguments, and reuse them, including quotes and quotes around the whole argument list.
I tried using \"$@\"
, but that removes the quotes inside the list.
How do I accomplish this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
使用
"$@"
会将参数替换为列表,而不用在空格上重新分割它们(调用 shell 脚本时它们被分割一次),如果您只想这样做,这通常正是您想要的将参数重新传递给另一个程序。请注意,这是一种特殊形式,只有当它完全以这种方式出现时才会被识别。如果您在引号中添加任何其他内容,结果将合并为一个参数。
Using
"$@"
will substitute the arguments as a list, without resplitting them on whitespace (they were split once when the shell script was invoked), which is generally exactly what you want if you just want to repass the arguments to another program.Note that this is a special form and is only recognized as such if it appears exactly this way. If you add anything else in the quotes the result will get combined into a single argument.
有两种安全的方法可以执行此操作:
1. Shell 参数扩展:
${variable@Q}:
通过
${variable@Q}
扩展变量时:示例:
请注意,如果向人类显示引用的文本,第二种方法会更清晰一些。
相关:对于 Bash,POSIX sh 和 Z shell(可执行
new\nline' 'single'\''quote' 'double"quote'zsh
):用单引号而不是反斜杠引用字符串2.
printf %q "$quote-me"
printf
支持内部引用。printf
的手册条目< /a> 说:示例:
请注意,如果向人类显示引用的文本,第二种方法会更清晰一些。
相关:对于 Bash,POSIX sh 和 Z shell(可执行
zsh
):用单引号而不是反斜杠引用字符串There are two safe ways to do this:
1. Shell parameter expansion:
${variable@Q}:
When expanding a variable via
${variable@Q}
:Example:
Note the second way is a bit cleaner if displaying the quoted text to a human.
Related: For Bash, POSIX sh and Z shell (executable
new\nline' 'single'\''quote' 'double"quote'zsh
): Quote string with single quotes rather than backslashes2.
printf %q "$quote-me"
printf
supports quoting internally. The manual's entry forprintf
says:Example:
Note the second way is a bit cleaner if displaying the quoted text to a human.
Related: For Bash, POSIX sh and Z shell (executable
zsh
): Quote string with single quotes rather than backslashesYuku 的答案仅在您满足以下条件时才有效脚本的唯一用户,而丹尼斯·威廉姆森的答案<如果您主要对打印字符串感兴趣,并且希望它们没有引号中的引号,那么 /a> 非常有用。
如果您想将所有参数作为一个大引号字符串参数传递给
bash
或su
的-c
参数,可以使用以下版本>:因此,所有参数都会在它们周围有一个引号(如果之前不存在的话也无害,为此目的),但我们也转义任何转义,然后转义任何已经存在于一个参数中的引号参数(语法
${var//from/to}
进行全局子字符串替换)。您当然可以只引用其中已经有空格的内容,但这在这里并不重要。像这样的脚本的一个实用程序是能够拥有一组特定的预定义环境变量(或者,使用 su,以特定用户身份运行某些内容,而无需对所有内容进行双引号的混乱)。
我有理由以 POSIX 方式以最少的分叉执行此操作,这导致了此脚本(最后一个 printf 输出用于调用该脚本的命令行,您应该能够复制粘贴为了使用等效参数调用它):
我切换到
''
因为 shell 也解释$
和!!
中的内容""-引号。Yuku's answer only works if you're the only user of your script, while Dennis Williamson's answer is great if you're mainly interested in printing the strings, and expect them to have no quotes-in-quotes.
Here's a version that can be used if you want to pass all arguments as one big quoted-string argument to the
-c
parameter ofbash
orsu
:So, all the arguments get a quote around them (harmless if it wasn't there before, for this purpose), but we also escape any escapes and then escape any quotes that were already in an argument (the syntax
${var//from/to}
does global substring substitution).You could of course only quote stuff which already had whitespace in it, but it won't matter here. One utility of a script like this is to be able to have a certain predefined set of environment variables (or, with su, to run stuff as a certain user, without that mess of double-quoting everything).
I had reason to do this in a POSIX way with minimal forking, which lead to this script (the last printf there outputs the command line used to invoke the script, which you should be able to copy-paste in order to invoke it with equivalent arguments):
I switched to
''
since shells also interpret things like$
and!!
in""
-quotes.如果可以安全地假设包含空格的参数必须(并且应该)被引用,那么您可以像这样添加它们:
这是一个示例运行:
您还可以插入文字使用 Ctrl-V Tab 和 Ctrl-V 制表符和换行符在双引号或单引号内按 Ctrl-J,而不是在
$'...'
中使用转义符。关于在 Bash 中插入字符的说明:如果您在 Bash 中使用 Vi 键绑定 (
set -o vi
)(Emacs 是默认设置 -set -o emacs
),您需要处于插入模式才能插入字符。在 Emacs 模式下,您始终处于插入模式。If it's safe to make the assumption that an argument that contains white space must have been (and should be) quoted, then you can add them like this:
Here is a sample run:
You can also insert literal tabs and newlines using Ctrl-V Tab and Ctrl-V Ctrl-J within double or single quotes instead of using escapes within
$'...'
.A note on inserting characters in Bash: If you're using Vi key bindings (
set -o vi
) in Bash (Emacs is the default -set -o emacs
), you'll need to be in insert mode in order to insert characters. In Emacs mode, you're always in insert mode.我需要这个来将所有参数转发给另一个解释器。
最终对我来说正确的是:
示例(当命名为forward.sh时):(
当然,我使用的实际脚本更复杂,在我的例子中涉及nohup和重定向等,但这是关键部分。)
I needed this for forwarding all arguments to another interpreter.
What ended up right for me is:
Example (when named as forward.sh):
(Of course the actual script I use is more complex, involving in my case nohup and redirections etc., but this is the key part.)
就像汤姆·黑尔所说的,一种方法这样做是通过
printf
使用%q
进行引号转义。例如:
send_all_args.sh
send_fewer_args.sh
receiver.sh
用法示例:
Like Tom Hale said, one way to do this is with
printf
using%q
to quote-escape.For example:
send_all_args.sh
send_fewer_args.sh
receiver.sh
Example usage:
只需使用:
例如:
Just use:
For example:
我将 unhammer 的示例更改为使用数组。
I changed unhammer's example to use array.
我的问题是类似的,我使用了这里发布的混合想法。
我们有一个带有 PHP 脚本的服务器,可以发送电子邮件。然后我们有第二个服务器通过 SSH 连接到第一个服务器并执行它。
两台服务器上的脚本名称相同,并且实际上都是通过 bash 脚本执行的。
在服务器 1(本地)bash 脚本上,我们只有:
它驻留在
/usr/local/bin/myscript
上,并由远程服务器调用。即使对于带有空格的参数它也能正常工作。但是在远程服务器上我们不能使用相同的逻辑,因为第一台服务器不会收到来自
"$@"
的引号。我使用 JohnMudd 和 Dennis Williamson 的想法来重新创建带有引号的选项和参数数组。我喜欢仅当项目中有空格时才添加转义引号的想法。因此,远程脚本运行时为:
请注意,我使用
"${CSMOPTS[@]}"
将选项数组传递到远程服务器。My problem was similar and I used mixed ideas posted here.
We have a server with a PHP script that sends e-mails. And then we have a second server that connects to the 1st server via SSH and executes it.
The script name is the same on both servers and both are actually executed via a bash script.
On server 1 (local) bash script we have just:
This resides on
/usr/local/bin/myscript
and is called by the remote server. It works fine even for arguments with spaces.But then at the remote server we can't use the same logic because the 1st server will not receive the quotes from
"$@"
. I used the ideas from JohnMudd and Dennis Williamson to recreate the options and parameters array with the quotations. I like the idea of adding escaped quotations only when the item has spaces in it.So the remote script runs with:
Note that I use
"${CSMOPTS[@]}"
to pass the options array to the remote server.引号由 Bash 解释,不会存储在命令行参数或变量值中。
如果您想使用带引号的参数,则每次使用它们时都必须引用它们:
Quotes are interpreted by Bash and are not stored in command line arguments or variable values.
If you want to use quoted arguments, you have to quote them each time you use them:
如果您需要从另一种编程语言将所有参数传递给 Bash(例如,如果您想要执行
bash -c
或emit_bash_code | bash),使用这个:
'\''
转义所有单引号字符。abc'def
的参数将被转换为'abc'\''def'
。字符'\''
解释如下:已经存在的引用以第一个第一个引号终止,然后转义的单引号\'
出现,然后是新的引用开始。If you need to pass all arguments to Bash from another programming language (for example, if you'd want to execute
bash -c
oremit_bash_code | bash
), use this:'\''
.The argument of
abc'def
will thus be converted to'abc'\''def'
. The characters'\''
are interpreted as following: the already existing quoting is terminated with the first first quote, then the escaped singular single quote\'
comes, then the new quoting starts.正如 Gary S. Weaver 所示他的源代码提示,技巧是使用参数“-c”调用 Bash,然后引用下一个。
例如
或
As Gary S. Weaver has shown in his source code tips, the trick is to call Bash with parameter '-c' and then quote the next.
E.g.
or
是的,似乎不可能保留引号,但对于我正在处理的问题来说,这是没有必要的。
我有一个 Bash 函数,它将递归地向下搜索文件夹并且 grep 对于字符串,问题是传递一个带有空格的字符串,例如“find this string”。将其传递给 Bash 脚本将获取基本参数 $n 并将其传递给 grep,这让 grep 相信这些是不同的参数。我解决这个问题的方法是利用以下事实:当您引用 Bash 来调用函数时,它将引号中的项目分组为单个参数。我只需要用引号修饰该参数并将其传递给 grep 命令。
如果您知道在 bash 中收到的参数需要在下一步中使用引号,则可以用引号进行装饰。
Yes, seems that it is not possible to ever preserve the quotes, but for the issue I was dealing with it wasn't necessary.
I have a Bash function that will search down folder recursively and grep for a string, the problem is passing a string that has spaces, such as "find this string". Passing this to the Bash script will then take the base argument $n and pass it to grep, this has grep believing these are different arguments. The way I solved this by using the fact that when you quote Bash to call the function it groups the items in the quotes into a single argument. I just needed to decorate that argument with quotes and pass it to the grep command.
If you know what argument you are receiving in bash that needs quotes for its next step you can just decorate with with quotes.
只需在带有双引号的字符串周围使用单引号即可:
因此单引号内的双引号也被解释为字符串。
但我建议将整个字符串放在单引号之间:
为了了解 shell 正在做什么或者解释脚本中的参数,您可以编写一个像这样的小脚本:
然后您将看到并测试,当使用不同的字符串调用脚本
Just use single quotes around the string with the double quotes:
So the double quotes of inside the single quotes were also interpreted as string.
But I would recommend to put the whole string between single quotes:
In order to understand what the shell is doing or rather interpreting arguments in scripts, you can write a little script like this:
Then you'll see and test, what's going on when calling a script with different strings