我正在使用Mac OS X的pbpaste
命令,它返回剪贴板的内容。我想创建一个shell脚本,它执行pbpaste
返回的每一行作为单独的bash命令。例如,假设剪贴板的内容包含以下几行文字:
echo 1234 >~/a.txt
echo 5678 >~/b.txt
我想要一个执行每个行的shell脚本,在我的主文件夹中创建两个文件a.txt和b.txt。经过大量的搜索和反复试验后,我已经达到了能够使用以下结构将单独的文本行分配到while
循环中的变量的程度:
pbpaste | egrep -o [^$]+ | while read l; do echo $l; done
按预期发送以下标准输出:
echo 1234 >~/a.txt
echo 5678 >~/b.txt
我不是简单地回显每一行文本,而是尝试使用以下构造执行它们:
pbpaste | egrep -o [^$]+ | while read l; do $l; done
我认为这将执行每一行(从而在我的主文件夹中创建两个文本文件a.txt和b.txt)。相反,第一个术语(echo
)似乎被解释为命令,其余的术语(nnnn >~/...
)似乎被集中在一起,好像它们是一个参数,导致发送以下内容标准输出没有创建任何文件:
1234 >~/a.txt
5678 >~/b.txt
如果我能帮助理解为什么我的构造不起作用以及可能有什么变化可以使它工作,我将不胜感激。
答案 0 :(得分:2)
[...]其余的条款(
nnnn >~/...
)似乎被混为一谈,就好像它们是一个参数一样,[...]
不完全是。该行实际上是在空白(或$IFS
指定的任何内容)上拆分的,但问题是重定向运算符>
不能从shell变量中获取。例如,此代码段:
gt='>'
echo $gt foo.txt
将打印> foo.txt
,而不是将换行符打印到foo.txt
。
你会遇到各种其他shell元字符的类似问题,比如引号。
你需要的是eval
builtin,它接受一个字符串,将其解析为shell命令,然后运行它:
pbpaste | egrep -o [^$]+ | while IFS= read -r LINE; do eval "$LINE"; done
(IFS=
和-r
以及$LINE
周围的双引号都是为了防止除eval
执行的处理之外的任何其他处理,以便例如内部空白引号将被保留。)
另一种可能性,取决于你需要的细节,只是将命令传递给一个新的Bash实例:
pbpaste | egrep -o [^$]+ | bash
编辑添加:就此而言,我发现您可以在一个批次中将所有内容传递给eval
;尽可能(根据你的评论)写pbpaste | bash
,你也可以写eval "$(pbpaste)"
。这将支持多行while
- 循环等,同时仍在当前shell中运行(如果您希望它能够引用shell参数,设置环境变量等等,则非常有用)。