如何在文本文件中扩展shell变量?

时间:2013-01-21 08:04:55

标签: bash shell unix solaris ksh

考虑一个ASCII文本文件(假设它包含非shell脚本语言的代码):

Text_File.msh:

spool on to '$LOG_FILE_PATH/logfile.log';
login 'username' 'password';
....

现在,如果这是一个shell脚本,我可以将它作为$ sh Text_File.msh运行,shell会自动扩展变量。 我想要做的是让shell扩展这些变量,然后创建一个新文件Text_File_expanded.msh,如下所示:

Text_File_expanded.msh:

spool on to '/expanded/path/of/the/log/file/../logfile.log';
login 'username' 'password';
....

考虑:

$ a=123
$ echo "$a"
123

从技术上讲,这应该可以解决问题:

$ echo "`cat Text_File.msh`" > Text_File_expanded.msh

...但它没有按预期工作,输出文件虽然与源相同。

所以我不确定如何实现这一点。我的目标是让我更容易维护嵌入在我的非shell脚本中的目录路径。 这些脚本不能包含任何UNIX代码,因为它不是由UNIX shell编译的。

10 个答案:

答案 0 :(得分:25)

此问题已在另一个帖子中提出,这是IMO的最佳答案:

export LOG_FILE_PATH=/expanded/path/of/the/log/file/../logfile.log
cat Text_File.msh | envsubst > Text_File_expanded.msh

如果在Mac上,请先安装gettextbrew install gettext

请参阅: Forcing bash to expand variables in a string loaded from a file

答案 1 :(得分:9)

如果Perl解决方案适合您:

示例文件:

$ cat file.sh
spool on to '$HOME/logfile.log';
login 'username' 'password';

解决方案:

$ perl -pe 's/\$(\w+)/$ENV{$1}/g' file.sh
spool on to '/home/user/logfile.log';
login 'username' 'password';

答案 2 :(得分:8)

这个解决方案不优雅,但它有效。创建一个脚本调用shell_expansion.sh:

echo 'cat <<END_OF_TEXT' >  temp.sh
cat "$1"                 >> temp.sh
echo 'END_OF_TEXT'       >> temp.sh
bash temp.sh >> "$2"
rm temp.sh

然后您可以按照以下方式调用此脚本:

bash shell_expansion.sh Text_File.msh Text_File_expanded.msh

答案 3 :(得分:8)

上述答案的一个限制是它们都需要将变量导出到环境中。以下是我提出的允许变量在当前shell脚本中的本地变量:

#!/bin/sh
FOO=bar;
FILE=`mktemp`; # Let the shell create a temporary file
trap 'rm -f $FILE' 0 1 2 3 15;   # Clean up the temporary file 

(
  echo 'cat <<END_OF_TEXT'
  cat "$@"
  echo 'END_OF_TEXT'
) > $FILE
. $FILE

上面的示例允许在命令行上命名的文件中替换变量$FOO。我相信它可以改进,但到目前为止这对我有用。

感谢以前的答案,他们的想法!

答案 4 :(得分:8)

如果你想要它在一行(我不是一个bash专家,所以可能有一些警告,但它适用于我尝试过的所有地方):

当test.txt包含

${line1}
${line2}

然后:

>line1=fark
>line2=fork
>value=$(eval "echo \"$(cat test.txt)\"")
>echo "$value"
line1 says fark
line2 says fork

显然,如果您只想打印它,可以取出额外的value=$()echo "$value"

答案 5 :(得分:1)

如果要翻译的变量已知并且数量有限,您可以自己进行翻译:

sed "s/\$LOG_FILE_PATH/$LOG_FILE_PATH/g" input > output

并且假设变量本身已经知道

答案 6 :(得分:1)

此解决方案允许您在输出文件中保留相同的格式

在脚本中复制并粘贴以下行

cat $1 | while read line
do
  eval $line
  echo $line
  eval echo $line
done | uniq | grep -v '\$'

这将读取作为参数逐行传递的文件,然后进行处理以尝试打印每一行两次: - 一次没有替代 - 一次替换变量。 然后删除重复的行 然后删除包含可见变量的行($)

答案 7 :(得分:0)

使用以下内容创建ascii文件test.txt:

Try to replace this ${myTestVariable1} 
bla bla
....

现在创建一个包含变量名称的文件“sub.sed”,例如

's,${myTestVariable1},'"${myTestVariable1}"',g;
s,${myTestVariable2},'"${myTestVariable2}"',g;
s,${myTestVariable3},'"${myTestVariable3}"',g;
s,${myTestVariable4},'"${myTestVariable4}"',g'

打开终端移动到包含test.txt和sub.sed的文件夹 定义要替换的变量的值

myTestVariable1=SomeNewText

现在调用sed替换该变量

sed "$(eval echo $(cat sub.sed))" test.txt > test2.txt

输出

$cat test2.txt

Try to replace this SomeNewText 
bla bla
....

答案 8 :(得分:0)

是的 eval 应该谨慎使用,但这为我的问题提供了这个简单的方法。下面是使用文件名的示例:

eval "echo \"$(<Text_File.msh)\""

出于我自己的目的,我使用 printf 而不是 echo ,但这应该可以解决问题。谢谢abyss.7提供解决我的问题的链接。希望对您有所帮助。

答案 9 :(得分:0)

#logfiles.list:

$EAMSROOT/var/log/LinuxOSAgent.log
$EAMSROOT/var/log/PanacesServer.log
$EAMSROOT/var/log/PanacesStrutsGUI.log

#我的程序:

cat logfiles.list | while read line
    do
        eval Eline=$line
        echo $Eline
    done