这工作正常:
$ eval 'echo "1" > ~/Desktop/in/foo'
但不是这个:
$ while IFS= read _cmd; do eval "$_cmd"; done < <(cat << EOF
'echo "1" > ~/Desktop/in/foo'
'echo "2" > ~/Desktop/in/bar'
EOF
)
bash: echo "1" > ~/Desktop/in/foo: No such file or directory
bash: echo "2" > ~/Desktop/in/bar: No such file or directory
如何解决?
更新
正如建议的那样,删除单引号是可行的,但不适用于这种变体(同上,仅用单引号将文件名括起来):
$ while IFS= read _cmd; do eval "$_cmd"; done < <(cat << EOF
echo "1" > ~/Desktop/in/foo (bis)
echo "2" > ~/Desktop/in/bar
EOF
)
连同提供的解决方案:
"$SHELL" << EOF
echo "1" > ~/Desktop/in/'foo (bis)'
echo "2" > ~/Desktop/in/bar
EOF
运行
eval 'echo "1" > ~/Desktop/in/foo'
时,shell 会删除单引号,然后eval
计算echo "1" > ~/Desktop/in/foo
.当您运行时
eval "$_cmd"
(在更新前的代码中),shell 会展开$_cmd
并删除双引号,然后eval
计算'echo "1" > ~/Desktop/in/foo'
. 注意单引号。您不想eval
看到它们,请将它们从此处的文档中删除。在您更新的代码中,您可能想要
eval
评估echo "1" > ~/Desktop/in/'foo (bis)'
,因此请使用此处文档中的这一行。好吧,“确切”通常不是正确的词。通常
<< EOF
(与 eg 相对<< 'EOF'
)扩展了此处文档中的变量和其他一些内容(您的示例中没有,但通常这是它的工作原理)。然后IFS= read _cmd
不是IFS= read -r _cmd
。最后eval
得到一个字符串,它不一定是您使用的确切字符串。逐行评估使得评估多行命令变得不可能。
除非您真的想依赖于您提供的字符串(
<< EOF
并且IFS= read
您知道自己在做什么),否则只需直接在脚本中编写代码即可。毕竟,您希望解释脚本的 shell 评估echo "1" > ~/Desktop/in/foo
. 它甚至不是你想要一些其他的 shell 进程。这里不需要这里的文档。我想另一个shell进程的预处理代码可能有意义(在某些情况下并且当你小心时),但是你应该使用 eg
bash << EOF
, notread
。另一件事:片段
done < <(cat << EOF
可以简化为done << EOF
(注意此更改需要)
从代码末尾删除)。