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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 21:16:03  来源:igfitidea点击:

Preserving whitespaces in a string as a command line argument

bashscriptingwhitespace

提问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 USERexec 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.

希望这可以帮助。