bash脚本中可能存在的间距问题。命令不会在脚本中运行,但会从输出中复制

时间:2011-10-05 02:13:43

标签: bash spacing

我在http://tldp.org上引用了一些关于bash的引用,并用Google搜索,直到我脸色发青。我也尝试了这个问题的每一个明显的引用方案,但没有任何作用。

问题似乎是在脚本末尾运行的命令中引用参数内的空格被解释为分隔符而不是引用空格。

看哪,这是我的剧本(我完全知道我是个菜鸟,所以评论我的风格和/或不必要的语法对我来说很酷,我会学习):

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

因此,如果我粘贴/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中使用记录的命令语法时,我的命令不起作用。

3 个答案:

答案 0 :(得分:1)

简短回答:见BashFAQ #50

答案很长:当bash解析一行时,它会在进行变量替换之前解析引号;因此,当您在变量中添加引号时,它们不会达到您所期望的效果。你实际上是在传递一个参数列表,包括'-m'''测试''事件'''-r' - 那些双引号不在参数周围,它们是 in 参数。

在这种情况下,最好的解决方案是在数组而不是字符串中构建命令。此外,在使用变量(例如文件名)时,请使用双引号,以防止混淆(如果它们包含空格)。通过这些更改(以及其他一些调整),这是我的脚本版本:

#!/bin/bash

date="$(date)"  # Backquotes are confusing, use $() instead
args=("$@")   # Save the args in an array rather than mushing them together in a string
MSEND_HOME=/home/patrol/Impact           #Path to the Impact Directory
MSEND_HOME="$HOME/tmp"           #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"   # Quotes not strictly needed here, but a good habbit
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 array;
#e.g., additionalSlots="slot1=value1;slot2=value2;slot3=value 3"  # Don't embed quotes
additionalSlots=""


cmd=("$MSEND_HOME/bin/msend")   # Build the command as an array, not a string
cmd+=(-q)   # Could equivalently use cmd=("${cmd[@]}" -q), but this is simpler
cmd+=(-l "$MSEND_HOME")

if [ $persistEnabled -eq 1 ]
then
  cmd+=(-j "$bufDir")
fi

cmd+=(-n "$cellName")
cmd+=(-a "$class")  # Possible bug: $2 and @3 aren't required, but they're getting added unconditionally
cmd+=(-m "$msg")    # These should probably be conditional, like additionalSlots
cmd+=(-r "$severity")

if [ -n "$additionalSlots" ]
then
  cmd+=(-b "$additionalSlots")
fi

"${cmd[@]}" || die "$date - msend exited with error $? | Original arguments:$(printf " %q" "${args[@]}") | Command:$(printf " %q" "${cmd[@]}")"
#echo "msend exited with error $? | Original arguments:$(printf " %q" "${args[@]}") | Command:$(printf " %q" "${cmd[@]}")"

答案 1 :(得分:0)

我认为arg在这项任务中出错:cmd="$cmd -m $msg"

将其更改为cmd="$cmd -m \"$msg\""

答案 2 :(得分:0)

好的,我没有立即看到确切的问题,但我可以告诉你它是什么;这个提示应该有所帮助。

请记住,shell引用机制只解释字符串一次。结果,如果你不小心,你认为“foo”“a”“b”实际上是“foo a b” - 也就是说,所有一个标记,而不是三个。

使用bash -x运行脚本,该脚本将在每个步骤显示shell实际看到的内容。