26

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

文本文件.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 编译的。

4

10 回答 10

50

这个问题已在另一个线程中提出,这是 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

请参阅: 强制 bash 扩展从文件加载的字符串中的变量

于 2015-10-02T18:19:52.553 回答
11

这个解决方案并不优雅,但它确实有效。创建一个脚本调用 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
于 2013-01-21T08:23:44.783 回答
11

如果你想要它在一行中(我不是 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".

于 2015-01-14T17:28:16.453 回答
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';
于 2013-01-21T08:24:25.080 回答
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上面的示例允许在命令行命名的文件中替换变量。我确信它可以改进,但到目前为止这对我有用。

感谢他们之前的两个答案的想法!

于 2013-07-04T05:21:06.497 回答
2

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

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

并且还假设变量本身是已知的

于 2014-11-23T16:59:37.600 回答
1

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

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

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

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

于 2017-04-24T12:10:28.817 回答
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
....
于 2015-12-31T17:13:49.390 回答
0

是的eval应该小心使用,但它为我的问题提供了这个简单的 oneliner。以下是使用您的文件名的示例:

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

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

于 2020-03-21T00:15:19.760 回答
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
于 2020-08-14T19:01:34.797 回答