我正在尝试将包含名称(如果可用)和电子邮件的两个列表与 bash(shell)中的标准电子邮件文本结合起来 (我不得不删除不相关的代码,因为它包含一些私有(private)信息,所以有些代码可能看起来不寻常。)
代码的前半部分检查是否有姓名列表和电子邮件列表。 如果没有可用的姓名,后半部分仅结合电子邮件地址和文本,如果姓名列表可用,它也会“尝试”结合姓名、电子邮件和文本。
f1 = 电子邮件列表和 f2 = 姓名列表。 正如您在下面代码的前半部分中看到的,如果列表可用,$f2 应该显示名称,但它不会在日志文件中显示任何内容。
我已经尝试解决这个问题两天了,但没有任何效果。当名称可用时,它总是输出为 "Hello ..." 而它应该是 "Hello John D..."
#FIRST HALF
if [ "$names" = "no" ]
then
text="Hello..."
elif [ "$names" = "yes" ]
then
text="Hello $f2..."
fi
#SECOND HALF
if [ "$names" = "no" ]
then
for i in $(cat $emaillist); do
echo "$text" >> /root/log
echo "$i" >> /root/log
done
elif [ "$names" = "yes" ]
then
paste $emaillist $namelist | while IFS="$(printf '\t')" read -r f1 f2
do
echo "$text" >> /root/log
echo "$f1" >> /root/log
done
fi
最佳答案
当您运行 text="Hello $f2"
时,$f2
会在分配时被查找;一个精确的字符串被分配给 text
,并且只有那个精确的字符串稍后在 echo "$text"
上使用。
这是非常理想的行为:如果 shell 变量的值可以运行任意代码,则不可能编写安全处理不受信任数据的 shell 脚本……但这确实意味着实现您的程序需要进行一些更改。
如果你想推迟求值(在扩展时查找 $f2
的值而不是赋值),根本不要使用 shell 变量:改用函数。
case $names in
yes) write_greeting() { echo "Hello $name..."; };;
*) write_greeting() { echo "Hello..."; };;
esac
while read -r name <&3 && read -r email <&4; do
write_greeting
echo "$email"
done 3<"$namelist" 4<"$emaillist" >>/root/log
上面代码的一些改进:
- 您不需要
paste
来同步读取两个流;您可以简单地在不同的文件描述符上打开它们(上面,选择了 FDs3
和4
;仅保留 0、1 和 2,因此可以选择更大的数字作为好吧)每个都有一个单独的read
命令。 - 在整个循环中只打开一次输出接收器(通过将重定向放在
done
之后)比每次你想写一行时都重新打开它要有效得多。< - 扩展,例如
"$namelist"
和"$emaillist"
,总是被引用;如果处理包含不寻常字符(包括空格和 glob 表达式)的文件名,或者如果IFS
处于非默认值,这会使代码更加可靠。
关于linux - 在分配变量后,稍后使用变量引用扩展字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52435330/