我正在尝试研究如何在字符串(从文件加载)中使bash(强制?)扩展变量。
我有一个名为“something.txt”的文件,内容为:
hello $FOO world
然后我跑
export FOO=42
echo $(cat something.txt)
返回:
hello $FOO world
即使变量已设置,它也没有扩展$ FOO。我无法评估或获取文件 - 因为它会尝试并执行它(它不是可执行的 - 我只是希望插入变量的字符串)。
有什么想法吗?
答案 0 :(得分:76)
我偶然发现了我认为这个问题的答案:envsubst
命令。
envsubst < something.txt
如果您的发行版中尚未提供,则
gettext
。@Rockallite - 我写了一个小包装脚本来处理&#39; \ $&#39;问题
(顺便说一句,有一个&#34;功能&#34; envsubst,解释于 https://unix.stackexchange.com/a/294400/7088 仅用于扩展输入中的一些变量,但是我 同意逃避例外更加方便。)
这是我的剧本:
#! /bin/bash
## -*-Shell-Script-*-
CmdName=${0##*/}
Usage="usage: $CmdName runs envsubst, but allows '\$' to keep variables from
being expanded.
With option -sl '\$' keeps the back-slash.
Default is to replace '\$' with '$'
"
if [[ $1 = -h ]] ;then echo -e >&2 "$Usage" ; exit 1 ;fi
if [[ $1 = -sl ]] ;then sl='\' ; shift ;fi
sed 's/\\\$/\${EnVsUbDolR}/g' | EnVsUbDolR=$sl\$ envsubst "$@"
答案 1 :(得分:25)
许多答案使用eval
和echo
类型的工作,但打破各种事物,例如多行,试图逃避shell元字符,逃避模板内部不打算由bash等扩展
我有同样的问题,并写了这个shell函数,据我所知,它正确地处理了一切。由于bash的命令替换规则,这仍将仅从模板中删除尾随换行符,但只要其他所有内容保持不变,我就永远不会发现这是一个问题。
apply_shell_expansion() {
declare file="$1"
declare data=$(< "$file")
declare delimiter="__apply_shell_expansion_delimiter__"
declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter"
eval "$command"
}
例如,您可以像parameters.cfg
一样使用它,它实际上是一个只设置变量的shell脚本,而template.txt
是一个使用这些变量的模板:
. parameters.cfg
printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt
在实践中,我将其用作一种轻量级模板系统。
答案 2 :(得分:16)
你可以尝试
echo $(eval echo $(cat something.txt))
答案 3 :(得分:10)
你不想打印每一行,你想评估它,以便Bash可以执行变量替换。
FOO=42
while read; do
eval echo "$REPLY"
done < something.txt
有关详细信息,请参阅help eval
或Bash手册。
答案 4 :(得分:4)
另一种方法(看起来很蹩脚,但无论如何我都把它放在这里):
将something.txt的内容写入临时文件,并在其周围包含echo语句:
something=$(cat something.txt)
echo "echo \"" > temp.out
echo "$something" >> temp.out
echo "\"" >> temp.out
然后将其重新输入变量:
RESULT=$(source temp.out)
并且$ RESULT将全部展开。但它似乎错了!
答案 5 :(得分:2)
如果您只想扩展变量引用(我自己的目标),您可以执行以下操作。
contents="$(cat something.txt)"
echo $(eval echo \"$contents\")
($ contents内的转义引号是关键)
答案 6 :(得分:2)
bash
方法,(Michael Neale's answer的单行变体),
使用进程&amp; 命令替换:
FOO=42 . <(echo -e echo $(<something.txt))
输出:
hello 42 world
请注意,不需要export
。
GNU sed
e
评估方法,如果 something.txt 有很多行:
FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
答案 7 :(得分:1)
$ eval echo $(cat something.txt)
hello 42 world
$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Copyright (C) 2007 Free Software Foundation, Inc.
答案 8 :(得分:1)
foo=45
file=something.txt # in a file is written: Hello $foo world!
eval echo $(cat $file)
答案 9 :(得分:0)
以下解决方案:
允许替换已定义的变量
保留未定义的未更改的变量占位符。这在自动部署期间尤其有用。
支持以下列格式替换变量:
${var_NAME}
$var_NAME
报告哪些变量未在环境中定义,并返回此类情况的错误代码
TARGET_FILE=someFile.txt;
ERR_CNT=0;
for VARNAME in $(grep -P -o -e '\$[\{]?(\w+)*[\}]?' ${TARGET_FILE} | sort -u); do
VAR_VALUE=${!VARNAME};
VARNAME2=$(echo $VARNAME| sed -e 's|^\${||g' -e 's|}$||g' -e 's|^\$||g' );
VAR_VALUE2=${!VARNAME2};
if [ "xxx" = "xxx$VAR_VALUE2" ]; then
echo "$VARNAME is undefined ";
ERR_CNT=$((ERR_CNT+1));
else
echo "replacing $VARNAME with $VAR_VALUE2" ;
sed -i "s|$VARNAME|$VAR_VALUE2|g" ${TARGET_FILE};
fi
done
if [ ${ERR_CNT} -gt 0 ]; then
echo "Found $ERR_CNT undefined environment variables";
exit 1
fi
答案 10 :(得分:0)
envsubst
是一个很好的解决方案(请参阅LenW的答案)。
就我而言,我需要替换文件的内容来替换变量名。 envsubst
要求将内容导出为环境变量,并且在导出大于一兆字节的环境变量时bash会出现问题。
使用cuonglm的solution来自另一个问题:
needle="doc1_base64" # The "variable name" in the file. (A $ is not needed.)
needle_file="doc1_base64.txt" # Will be substituted for the needle
haystack=$requestfile1 # File containing the needle
out=$requestfile2
awk "BEGIN{getline l < \"${needle_file}\"}/${needle}/{gsub(\"${needle}\",l)}1" $haystack > $out
此解决方案甚至适用于大文件。
答案 11 :(得分:-1)
expenv () {
LF=$'\n'
echo "cat <<END_OF_TEXT${LF}$(< "$1")${LF}END_OF_TEXT" | bash
return $?
}
expenv "file name"
答案 12 :(得分:-2)
以下作品:bash -c "echo \"$(cat something.txt)"\"