简体   繁体   English

Bash:扩展变量,但不包括特殊字符

[英]Bash: expand variables, but not special characters

I have a bash script that creates and executes an expect script by stitching together dozens of different files containing pieces of expect code. 我有一个bash脚本,它通过将包含expect代码段的数十个不同文件拼接在一起来创建和执行expect脚本。 Those files contain environment variables that need to be expanded. 这些文件包含需要扩展的环境变量。 Example: 例:

expect.piece: expect.piece:

send "command\r"
sleep $timeout
send "command argument\r"

script.sh: script.sh:

#let's try it like this
eval echo $(cat expect.piece)
#or maybe like this
eval "echo \"$(cat expect.piece)\""

output: 输出:

send command\r sleep 1 send command argument\r
send commandr
sleep 1
send command argumentr

Desired otput: 所需的输出量:

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

I need a solution without sed string substitution (there is a lot of environment variables) and without modifying original expect script files. 我需要一个没有sed字符串替换(有很多环境变量)并且没有修改原始的expect脚本文件的解决方案。 I guess it could be done line by line, but is there a more elegant solution? 我想可以逐行完成,但是有没有更优雅的解决方案?

Default field separator in bash is a space so set input file separator as a new line like IFS=$(echo -e '\\n') before executing eval echo $(cat expect.piece) . bash中的默认字段分隔符是一个space因此在执行eval echo $(cat expect.piece)之前,将输入文件分隔符设置为新行,例如IFS=$(echo -e '\\n') eval echo $(cat expect.piece)

Final script would be : 最终脚本为:

#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

There is one another way which you can put your expect code with -c flag in the shell script as shown below. 您可以使用另一种方式将带有-c标志的expect代码放入shell脚本中,如下所示。

script.sh script.sh

#Calling the expect.piece file code here
expect -c expect.piece

You can make use of the optional command line values as , 您可以将可选命令行值用作,

expect -c "set count 1" myscript.exp

where the variable count will be used in the expect script file myscript.exp . expect脚本文件myscript.exp中将使用变量count

You can directly give the whole code as 您可以直接将整个代码作为

expect -c "
             send \"command\r\"
             sleep $timeout
             send \"command argument\r\"
"

Notice the use of backslash to escape the double quotes wherever needed. 请注意,在需要时使用反斜杠来转义双引号。 Single quotes can also be used. 也可以使用单引号。 But, if you use double quotes, then only shell substitution can happen. 但是,如果使用双引号,则只能进行shell替换。

Please refer here to know more about the -c flag in expect . 请参考这里了解更多关于-cexpect

It's not clear from your question in what context you want this output. 从您的问题尚不清楚您需要此输出的上下文。 If it's okay to embed the Expect script as a here document, what you want is trivial. 如果可以将Expect脚本嵌入到此处文档中,那么您想要的只是微不足道的。

#!/bin/sh

timeout=1

cat <<____HERE
send "command\r"
sleep $timeout
send "command argument\r"
____HERE

(Maybe you can even replace the cat with expect but I'm not familiar enough with Expect to make any recommendations.) (也许你甚至可以取代catexpect ,但我没有足够的熟悉,希望提出任何建议。)

If you need to take the input from a file, and only have a limited set of variables you want expanded, you could do that with sed . 如果您需要从文件中获取输入,并且只需要扩展一组有限的变量,则可以使用sed

sed "s/\$timeout/$timeout/g" file

If you need a more general solution, you might want to swich to Perl: 如果您需要更通用的解决方案,则可以使用Perl:

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

but this requires you to export (or otherwise expose to Perl) the shell environment variables you want exported. 但这要求您export (或以其他方式公开给Perl)要导出的Shell环境变量。 (This will just not substitute any undefined variables; change the value after || if you want to change that aspect of the behavior.) (这将不会替代任何未定义的变量;如果要更改行为的这一方面,请更改||之后的值。)

I invented the solution for this problem, it is a kludge, but it works. 我发明了解决这个问题的方法,虽然很麻烦,但是可以解决。

expect.piece: expect.piece:

sleep $timeout
send "foo bar\r"
send "$(date)\r"

script.sh: script.sh:

timeout=1
eval echo $(sed " \
s/\\\/\\\\\\\/g; \
s/\"/\\\\\"/g; \
s/\"/\\\\\`/\"/\\\\\`/g; \
" "expect.piece" | tr '\n' '+') | tr '+' '\n'

output: 输出:

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

First, we need to escape all the backslashes, backticks and quotes in the file, because they will be removed during the evaluation. 首先,我们需要转义文件中的所有反斜杠,反引号和引号,因为它们将在评估期间被删除。 Then, we need to replace all the newline characters with pluses, in order to make it in a single line. 然后,我们需要将所有换行符替换为加号,以使其成为一行。 After that, we evaluate that line (the evaluation will "expand" all the environment variables and command substitutions) and replace pluses back to newlines. 之后,我们评估该行(评估将“扩展”所有环境变量和命令替换)并将加号替换回换行。

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

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