Bash:展开变量,但不展开特殊字符

Bash:展开变量,但不展开特殊字符,bash,variables,eval,expect,expand,Bash,Variables,Eval,Expect,Expand,我有一个bash脚本,它通过将包含expect代码片段的几十个不同文件拼接在一起,创建并执行expect脚本。这些文件包含需要展开的环境变量。例如: expect.piece: send "command\r" sleep $timeout send "command argument\r" sleep $timeout send "foo bar\r" send "$(date)\r" script.sh: #let's try it like this eval echo $(cat e

我有一个bash脚本,它通过将包含expect代码片段的几十个不同文件拼接在一起,创建并执行expect脚本。这些文件包含需要展开的环境变量。例如:

expect.piece:

send "command\r"
sleep $timeout
send "command argument\r"
sleep $timeout
send "foo bar\r"
send "$(date)\r"
script.sh:

#let's try it like this
eval echo $(cat expect.piece)
#or maybe like this
eval "echo \"$(cat expect.piece)\""
timeout=1
eval echo $(sed " \
s/\\\/\\\\\\\/g; \
s/\"/\\\\\"/g; \
s/\"/\\\\\`/\"/\\\\\`/g; \
" "expect.piece" | tr '\n' '+') | tr '+' '\n'
输出:

send command\r sleep 1 send command argument\r
send commandr
sleep 1
send command argumentr
sleep 1
send "foo bar\r"
send "Wed Feb 18 03:19:24  2015\r"
期望输出:

send "command\r"
sleep 1
send "command argument\r"

我需要一个没有sed字符串替换的解决方案有很多环境变量,并且不修改原始的expect脚本文件。我想可以逐行执行,但有没有更优雅的解决方案?

bash中的默认字段分隔符是一个空格,因此在执行eval echo$cat expect.piece之前,将输入文件分隔符设置为一个新行,如IFS=$echo-e'\n'

最后的脚本是:

#Storing original field separator in variable OFS
OFS=$IFS
#Setting IFS as new line using echo -e. Unfortunately IFS="\n" does not work in bash
IFS=$(echo -e '\n')
eval echo $(cat expect.piece)
#Resetting the field separator as space
IFS=$OFS

还有一种方法可以将带有-c标志的expect代码放入shell脚本中,如下所示

script.sh

您可以使用以下可选命令行值:

expect -c "set count 1" myscript.exp
其中变量计数将在预期脚本文件myscript.exp中使用

您可以直接将整个代码作为

expect -c "
             send \"command\r\"
             sleep $timeout
             send \"command argument\r\"
"
请注意,在需要时使用反斜杠来转义双引号。也可以使用单引号。但是,如果使用双引号,则只能进行shell替换


请参阅expect中的“了解有关-c标志的更多信息”。

您的问题不清楚您希望在什么上下文中获得此输出。如果可以将Expect脚本嵌入为here文档,那么您所需要的就很简单了

#!/bin/sh

timeout=1

cat <<____HERE
send "command\r"
sleep $timeout
send "command argument\r"
____HERE
如果需要更通用的解决方案,您可能希望切换到Perl:

perl -pe 's/\$(\w+)/$ENV{$1} || "\$$1" /ge' file

但这需要导出或以其他方式向Perl公开要导出的shell环境变量。这不会替代任何未定义的变量;如果要更改行为的这一方面,请更改| |之后的值。

我发明了解决此问题的方法,这是一个难题,但它是有效的

expect.piece:

send "command\r"
sleep $timeout
send "command argument\r"
sleep $timeout
send "foo bar\r"
send "$(date)\r"
script.sh:

#let's try it like this
eval echo $(cat expect.piece)
#or maybe like this
eval "echo \"$(cat expect.piece)\""
timeout=1
eval echo $(sed " \
s/\\\/\\\\\\\/g; \
s/\"/\\\\\"/g; \
s/\"/\\\\\`/\"/\\\\\`/g; \
" "expect.piece" | tr '\n' '+') | tr '+' '\n'
输出:

send command\r sleep 1 send command argument\r
send commandr
sleep 1
send command argumentr
sleep 1
send "foo bar\r"
send "Wed Feb 18 03:19:24  2015\r"

首先,我们需要转义文件中的所有反斜杠、反勾号和引号,因为它们将在计算过程中被删除。然后,我们需要用加号替换所有换行符,以便使其成为一行。在那之后,我们对该行求值。求值将展开所有环境变量和命令替换,并将加号替换回换行符。

您是要执行所需的输出,还是只想在bash脚本中打印它?因为eval将尝试执行echo命令的输出,也就是说,它将尝试执行send-in-bash脚本,这是一个expect的命令,而不是bash的命令。我需要创建一个脚本,稍后将使用expect执行。bash对这种模板扩展没有很好的支持。相反,将变量保留在expect.piece中,并确保在适当的环境中执行它,例如timeout的值为1。好的,但是如果我有这样一个巨大的替换队列,那么让我们重新考虑sed,它仍然没有脱离主题:sed s/\$timeout/$timeout/g;s/\$var/$var/g虽然有效,但是有很多变量可以简化,用$whater的值替换\$whater吗?我已经尝试过了,就像其他许多实验一样,它产生了:-sh:send:command未找到因为send是一个expect命令,您不能在bash中使用它,您需要使用expect的解释器来运行它。