简体   繁体   English

保留字符串中的空格作为命令行参数

[英]Preserving whitespaces in a string as a command line argument

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 ---------#

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 . bash-hackers.org wiki有一个关于这个主题好页面 It looks to me like the most useful one here is to put the command in an array rather than a simple variable: 在我看来,最有用的是将命令放在数组而不是简单的变量中:

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运行命令。不要这样做;这是引入奇怪的解析错误的好方法。)

I have a suggestion: 我有一个建议:

# iterate through the passed arguments, save them to new properly quoted ARGS string
while [ -n "$1" ]; do
   ARGS="$ARGS '$1'"
   shift
done

# invoke the command with properly quoted arguments
my_command $ARGS

probably you need to surround the argument by double quotes (eg "${6}"). 可能你需要用双引号括起参数(例如“$ {6}”)。

Following OP comment it should be "$BLACKRAY_END_POINT" OP评论之后应该是“$ BLACKRAY_END_POINT”

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 $1
grep $1 test.txt
echo

echo "With quotes in script"
echo "$1"
grep "$1" 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.txt which interpreted "words" as a filename in addition to "test.txt". 您可以看到在“无引号”部分中,它尝试使用grep two words test.txt ,除了“test.txt”之外,还将“words”解释为文件名。 Also, the echo dropped the extra spaces. 此外, echo丢弃了额外的空间。

When the parameter is quoted, as in the second section, grep saw it as one argument (including the extra spaces) and handled it correctly. 当引用参数时,如第二部分所示, grep将其视为一个参数(包括额外的空格)并正确处理它。 And echo preserved the extra spaces. echo保留了额外的空间。

I used the extra spaces, by the way, merely to aid in the demonstration. 顺便说一下,我使用了额外的空间来帮助演示。

Below is my example of restarting a script via exec su USER or exec su - USER . 下面是我通过exec su USERexec su - USER重新启动脚本的示例。 It accommodates: 它适用于:

  • 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 "$0")' $(printf " %q" "$@")" - $user
  exit $?
fi

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> VAR1="abc        def    gh ijk"
bash> echo $VAR1
abc def gh ijk
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 IFS bypass: 使用IFS旁路:

bash> IFS='%'
bash> echo $VAR1
abc        def    gh ijk
bash>unset IFS
bash>

It works wonderfully for my command case: 它对我的命令案例非常有用:

su - user1 -c 'test -r "'${filepath}'"; ....'

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM