bash 保留字符串中的空格作为命令行参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1554160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Preserving whitespaces in a string as a command line argument
提问by crozzfire
I'm facing a small problem here, I want to pass a string containing whitespaces , to another program such that the whole string is treated as a command line argument.
我在这里面临一个小问题,我想将包含空格的字符串传递给另一个程序,以便将整个字符串视为命令行参数。
In short I want to execute a command of the following structure through a bash shell script: command_name -a arg1 -b arg2 -c "arg with whitespaces here"
简而言之,我想通过 bash shell 脚本执行以下结构的命令: command_name -a arg1 -b arg2 -c "arg with whitespaces here"
But no matter how I try, the whitespaces are not preserved in the string, and is tokenized by default. A solution please,
但是无论我如何尝试,空格都不会保留在字符串中,并且默认情况下会被标记化。求解决办法,
edit: This is the main part of my script:
编辑:这是我的脚本的主要部分:
#!/bin/bash
#-------- BLACKRAY CONFIG ---------------#
# Make sure the current user is in the sudoers list
# Running all instances with sudo
BLACKRAY_BIN_PATH='/opt/blackray/bin'
BLACKRAY_LOADER_DEF_PATH='/home/crozzfire'
BLACKRAY_LOADER_DEF_NAME='load.xml'
BLACKRAY_CSV_PATH='/home/crozzfire'
BLACKRAY_END_POINT='default -p 8890'
OUT_FILE='/tmp/out.log'
echo "The current binary path is $BLACKRAY_BIN_PATH"
# Starting the blackray 0.9.0 server
sudo "$BLACKRAY_BIN_PATH/blackray_start"
# Starting the blackray loader utility
BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "\"$BLACKRAY_END_POINT\"""
sudo time $BLACKRAY_INDEX_CMD -a $OUT_FILE
#--------- END BLACKRAY CONFIG ---------#
回答by Gordon Davisson
You're running into this problem because you store the command in a variable, then expand it later; unless there's a good reason to do this, don't:
您遇到这个问题是因为您将命令存储在一个变量中,然后再展开它;除非有充分的理由这样做,否则不要:
sudo time $BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT" -a $OUT_FILE
If you really do need to store the command and use it later, there are several options; the bash-hackers.org wiki has a good page on the subject. It looks to me like the most useful one here is to put the command in an array rather than a simple variable:
如果您确实需要存储命令并在以后使用它,则有多种选择;bash-hackers.org wiki在这个主题上有一个很好的页面。在我看来,这里最有用的方法是将命令放入数组而不是简单的变量中:
BLACKRAY_INDEX_CMD=($BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT")
sudo time "${BLACKRAY_INDEX_CMD[@]}" -a $OUT_FILE
This avoids the whole confusion between spaces-separating-words and spaces-within-words because words aren't separated by spaces -- they're in separate elements of the array. Expanding the array in double-quotes with the [@]suffix preserves that structure.
这避免了空格分隔单词和单词内空格之间的整个混淆,因为单词不是用空格分隔的——它们位于数组的单独元素中。用带[@]后缀的双引号扩展数组会保留该结构。
(BTW, another option would be to use escaped quotes rather like you're doing, then run the command with eval. Don't do this; it's a good way to introduce weird parsing bugs.)
(顺便说一句,另一种选择是使用转义引号而不是像您正在做的那样,然后使用 运行命令eval。不要这样做;这是引入奇怪的解析错误的好方法。)
回答by Pavel
I have a suggestion:
我有一个建议:
# iterate through the passed arguments, save them to new properly quoted ARGS string
while [ -n "" ]; do
ARGS="$ARGS ''"
shift
done
# invoke the command with properly quoted arguments
my_command $ARGS
回答by Paused until further notice.
Edit:
编辑:
Try:
尝试:
BLACKRAY_END_POINT="'default -p 8890'"
or
或者
BLACKRAY_END_POINT='"default -p 8890"'
or
或者
BLACKRAY_END_POINT="default\ -p\ 8890"
or
或者
BLACKRAY_END_POINT='default\ -p\ 8890'
and
和
BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e $BLACKRAY_END_POINT"
Original answer:
原答案:
Is blackray_loader a shell script?
blackray_loader 是 shell 脚本吗?
Here is a demonstration that you have to deal with this issue both when specifying the parameter and when handling it:
这是一个演示,您必须在指定参数和处理参数时处理此问题:
A text file called "test.txt" (include the line numbers):
一个名为“test.txt”的文本文件(包括行号):
1 two words
2 two words
3 two
4 words
A script called "spacetest":
一个名为“spacetest”的脚本:
#!/bin/bash
echo "No quotes in script"
echo
grep test.txt
echo
echo "With quotes in script"
echo ""
grep "" test.txt
echo
Running it with ./spacetest "two--------words"(replace the hyphens with spaces):
运行它./spacetest "two--------words"(用空格替换连字符):
No quotes in script
two words
grep: words: No such file or directory
test.txt:1 two words
test.txt:2 two words
test.txt:3 two
With quotes in script
two words
2 two words
You can see that in the "No quotes" section it tried to do grep two words test.txtwhich interpreted "words" as a filename in addition to "test.txt". Also, the echodropped the extra spaces.
您可以看到,在“无引号”部分,它尝试将grep two words test.txt“words”解释为“test.txt”之外的文件名。此外,echo删除了额外的空格。
When the parameter is quoted, as in the second section, grepsaw it as one argument (including the extra spaces) and handled it correctly. And echopreserved the extra spaces.
当参数被引用时,如第二部分,grep将其视为一个参数(包括额外的空格)并正确处理它。并echo保留了额外的空间。
I used the extra spaces, by the way, merely to aid in the demonstration.
顺便说一下,我使用了额外的空格,只是为了帮助演示。
回答by dimba
probably you need to surround the argument by double quotes (e.g. "${6}").
可能您需要用双引号将参数括起来(例如“${6}”)。
Following OP comment it should be "$BLACKRAY_END_POINT"
在 OP 评论之后,它应该是“$BLACKRAY_END_POINT”
回答by Wiseguy
Below is my example of restarting a script via exec su USERor exec su - USER. It accommodates:
下面是我通过exec su USER或exec su-USER重新启动脚本的示例。它容纳:
- being called from a relative path or current working directory
- spaces in script name and arguments
- single and double-quotes in arguments, without crazy escapes like: \\"
- 从相对路径或当前工作目录调用
- 脚本名称和参数中的空格
- 参数中的单引号和双引号,没有疯狂的转义,例如:\\"
#
# This script should always be run-as a specific user
#
user=jimbob
if [ $(whoami) != "$user" ]; then
exec su -c "'$(readlink -f "bash> VAR1="abc def gh ijk"
bash> echo $VAR1
abc def gh ijk
bash>
")' $(printf " %q" "$@")" - $user
exit $?
fi
回答by Kloe2378231
A post on other blog saved me for this whitespaces problem: http://logbuffer.wordpress.com/2010/09/23/bash-scripting-preserve-whitespaces-in-variables/
其他博客上的一篇文章为我解决了这个空格问题:http: //logbuffer.wordpress.com/2010/09/23/bash-scripting-preserve-whitespaces-in-variables/
By default, whitespaces are trimed:
默认情况下,会修剪空格:
bash> IFS='%'
bash> echo $VAR1
abc def gh ijk
bash>unset IFS
bash>
"The cause of this behaviour is the internal shell variable $IFS (Internal Field Separator), that defaults to whitespace, tab and newline. To preserve all contiguous whitespaces you have to set the IFS to something different"
“这种行为的原因是内部 shell 变量$IFS(内部字段分隔符),它默认为空格、制表符和换行符。要保留所有连续的空格,您必须将 IFS 设置为不同的内容”
With IFSbypass:
使用IFS绕过:
su - user1 -c 'test -r "'${filepath}'"; ....'
It works wonderfully for my command case:
它非常适合我的命令案例:
##代码##Hope this helps.
希望这可以帮助。

