bash 脚本中可能存在间距问题。命令不会在脚本中运行,但会在从输出复制时运行
我在 http://tldp.org 上转了一圈又一圈地引用了 bash 的内容,并用谷歌搜索,直到我感到沮丧在脸上。我还尝试了针对此问题的所有明显的引用方案,但没有任何效果。
问题似乎是在脚本末尾运行的命令中带引号的参数内的空格被解释为分隔符而不是带引号的空格。
看哪,这是我的脚本(我很清楚我是个菜鸟,所以对我的风格和/或不必要的语法的评论对我来说很酷,我会学习):
#!/bin/bash
date=`date`
args="$@"
MSEND_HOME=/home/patrol/Impact #Path to the Impact Directory
integrationName=Introscope #Name of the integration
persistEnabled=1 #1 for Yes, 0 for No
persist=""
bufDir=$MSEND_HOME/tmp/$integrationName #DO NOT CHANGE
cellName=linuxtest #Cell name to forward events to
loggingEnabled=1 #1 for Yes, 0 for No
logFile=$MSEND_HOME/log/$integrationName.$cellName.log
die () {
if [ $loggingEnabled -eq 1 ]
then
echo >>$logFile "$@"
fi
exit 1
}
[ "$#" -ge 1 ] || die "$date - At least 1 argument required, $# provided" "$@"
# This is where you would parse out your arguments and form the following
# slots as a minimum for sending an event.
class=$2
msg=\"$3\"
# Parse the first argument and assign the correct syntax
if [[ $1 == "INFORMATIONAL" ]]
then
severity=INFO
elif [[ $1 == "WARN" ]]
then
severity=WARNING
elif [[ $1 == "CRIT" ]]
then
severity=CRITICAL
else
severity=INFO
fi
#Additional slots can be set, parse them all in this variable;
#e.g., additionalSlots="slot1=value1;slot2=value2;slot3=\"value 3\""
additionalSlots=""
cmd="$MSEND_HOME/bin/msend"
cmd="$cmd -q"
cmd="$cmd -l $MSEND_HOME"
if [ $persistEnabled -eq 1 ]
then
cmd="$cmd -j $bufDir"
fi
cmd="$cmd -n $cellName"
cmd="$cmd -a $class"
cmd="$cmd -m $msg"
cmd="$cmd -r $severity"
if [ $additionalSlots ]
then
cmd="$cmd -b $additionalSlots"
fi
$cmd || die "$date - msend exited with error $? | Original arguments: $args | Command: $cmd"
#echo "msend exited with error $? | Original arguments: $args | Command: $cmd"
脚本的执行方式如下:
./sendEvent。 sh "CRIT" "EVENT" "Test Event"
我从 msend 可执行文件中得到的错误是参数错误,但我将命令行完整记录到一个文件中,当我运行该记录时命令在shell 交互,它可以工作。
以下是日志输出:
Tue Oct 4 20:31:29 CDT 2011 - msend exited with error 27 |原论点:CRIT EVENT 测试事件 |命令: /home/patrol/Impact/bin/msend -q -l /home/patrol/Impact -j /home/patrol/Impact/tmp/Introscope -n linuxtest -a EVENT -m "测试事件" -r CRITICAL< /code>
因此,如果我粘贴 /home/patrol/Impact/bin/msend -q -l /home/patrol/Impact -j /home/patrol/Impact/tmp/Introscope -n linuxtest -a EVENT -m "Test Event" -r CRITICAL 并运行它,它可以工作。
如果我运行像 ./sendEvent.sh "CRIT" "EVENT" "TestEvent"
这样的脚本,它就会起作用。但我需要这个参数来留出空间。
我发现这是 $IFS 问题或其他问题...也许是交互式 shell 和脚本环境之间的差异。
我很感激比我聪明的人提供任何见解!
tl;dr - 我的命令在从脚本内运行时不起作用,但在交互式 shell 中使用记录的命令语法时起作用。
I've gone around and around on the quoting stuff on http://tldp.org for bash and googled until I am blue in the face. I've also tried every obvious quoting scheme for this issue, and yet nothing works.
The problem seems to be that a space inside of a quoted argument in the command run at the end of the script is being interpreted as a separator instead of as a quoted space.
Behold, here's my script (I know full well I'm a noob so comments on my style and/or uneccessary syntax is cool with me, I'll learn):
#!/bin/bash
date=`date`
args="$@"
MSEND_HOME=/home/patrol/Impact #Path to the Impact Directory
integrationName=Introscope #Name of the integration
persistEnabled=1 #1 for Yes, 0 for No
persist=""
bufDir=$MSEND_HOME/tmp/$integrationName #DO NOT CHANGE
cellName=linuxtest #Cell name to forward events to
loggingEnabled=1 #1 for Yes, 0 for No
logFile=$MSEND_HOME/log/$integrationName.$cellName.log
die () {
if [ $loggingEnabled -eq 1 ]
then
echo >>$logFile "$@"
fi
exit 1
}
[ "$#" -ge 1 ] || die "$date - At least 1 argument required, $# provided" "$@"
# This is where you would parse out your arguments and form the following
# slots as a minimum for sending an event.
class=$2
msg=\"$3\"
# Parse the first argument and assign the correct syntax
if [[ $1 == "INFORMATIONAL" ]]
then
severity=INFO
elif [[ $1 == "WARN" ]]
then
severity=WARNING
elif [[ $1 == "CRIT" ]]
then
severity=CRITICAL
else
severity=INFO
fi
#Additional slots can be set, parse them all in this variable;
#e.g., additionalSlots="slot1=value1;slot2=value2;slot3=\"value 3\""
additionalSlots=""
cmd="$MSEND_HOME/bin/msend"
cmd="$cmd -q"
cmd="$cmd -l $MSEND_HOME"
if [ $persistEnabled -eq 1 ]
then
cmd="$cmd -j $bufDir"
fi
cmd="$cmd -n $cellName"
cmd="$cmd -a $class"
cmd="$cmd -m $msg"
cmd="$cmd -r $severity"
if [ $additionalSlots ]
then
cmd="$cmd -b $additionalSlots"
fi
$cmd || die "$date - msend exited with error $? | Original arguments: $args | Command: $cmd"
#echo "msend exited with error $? | Original arguments: $args | Command: $cmd"
The script is executed like this:
./sendEvent.sh "CRIT" "EVENT" "Test Event"
The error I get from the msend executable is that the arguments are wrong, but I'm logging the command line in it's entirety to a file and when I run that logged command in the shell interactively, it works.
Here's the log output:
Tue Oct 4 20:31:29 CDT 2011 - msend exited with error 27 | Original arguments: CRIT EVENT Test Event | Command: /home/patrol/Impact/bin/msend -q -l /home/patrol/Impact -j /home/patrol/Impact/tmp/Introscope -n linuxtest -a EVENT -m "Test Event" -r CRITICAL
So if I paste /home/patrol/Impact/bin/msend -q -l /home/patrol/Impact -j /home/patrol/Impact/tmp/Introscope -n linuxtest -a EVENT -m "Test Event" -r CRITICAL
and run it, it works.
If I run the script like ./sendEvent.sh "CRIT" "EVENT" "TestEvent"
it works. But I need that argument to allow spaces.
I'm on the track that it's an $IFS issue or something... maybe a difference between the interactive shell and the script environment.
I'd appreciate any insight from smarter people than me!
tl;dr - My command doesn't work when run from within a script, but does when the logged command syntax is used in an interactive shell.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
简短回答:请参阅 BashFAQ #50。
长答案:当 bash 解析一行时,它会在进行变量替换之前解析引号;因此,当您在变量中添加引号时,它们不会执行您所期望的操作。您实际上传递了一个参数列表,其中包括 '-m' '"Test' 'Event"' '-r' - 这些双引号不在参数周围,它们在中论据。
在这种情况下,最好的解决方案是在数组而不是字符串中构建命令。另外,养成在使用变量(例如文件名)时使用双引号的习惯,以防止在变量包含空格时出现混淆。经过这些更改(以及一些其他调整),这是我的脚本版本:
Short answer: see BashFAQ #50.
Long answer: When bash parses a line, it parses quote marks before doing variable substitution; as a result, when you put quotes inside a variable, they don't do what you'd expect. You're actually passing an argument list including '-m' '"Test' 'Event"' '-r' -- those double-quotes aren't around the arguments, they're in the arguments.
In this case, the best solution is to build the command in an array rather than a string. Also, get in the habbit of putting double-quotes around variables (e.g. filenames) when you use them, to prevent confusion if they contain spaces. With those changes (and a few other tweaks), here's my version of your script:
我认为这个分配的参数出了问题:
cmd="$cmd -m $msg"
。将其更改为
cmd="$cmd -m \"$msg\""
。I think the arg goes wrong with this assignment:
cmd="$cmd -m $msg"
.Change it to
cmd="$cmd -m \"$msg\""
.好吧,我没有立即看到确切的问题,但我可以告诉你它是什么;这个提示应该有帮助。
请记住,shell 引用机制仅解释字符串一次。结果,如果你不小心,你以为的“foo”“a”“b”实际上是“foo a b”——也就是说,都是一个标记,而不是三个。
使用 bash -x 运行脚本,这将在每一步向您显示 shell 实际看到的内容。
Okay, I don't see the exact problem immediately, but I can tell you what it is; this hint should help.
Remember that the shell quoting mechanism only interprets a string once. As a result, if you're not careful, what you thought was "foo" "a" "b" is in fact "foo a b" -- that is, all one token, not three.
Run the script with
bash -x
which will show you at each step what the shell is actually seeing.