在 中bash
,括号扩展在执行命令之前作为 shell 操作执行。1这意味着以下内容将起作用:
echo {1..10} >output | at -m now
输出将为1 2 3 4 5 6 7 8 9 10
.
不起作用的是尝试在at
命令中执行大括号扩展,该命令警告命令将由 执行/bin/sh
,在我的情况下,它链接到dash
似乎不支持使用大括号进行范围扩展。
$ at - now
warning: commands will be executed using /bin/sh
at> echo {1..10} >output
at> <EOT>
dash
这将在(或 Bourne 或您链接到的任何 shell )中运行命令,/bin/sh
产生输出{1..10}
.
以这种方式使用命令时如何执行大括号扩展at
?
除了我作为答案发布的解决方案之外,我有兴趣看到其他解决方案,例如能够bash
在at
提示符中执行命令。为从提示符运行的每个单行命令创建一个脚本似乎比需要付出更多的努力at
。
答案1
还有三个简单的其他选项。一个有点脆弱,依赖于 shell 的实现细节,另一个使用这里的文件提供bash
内联脚本,另一个仅用于-c
传入一行。
最可靠、最便携的是,使用这里的文档:
$ at now
warning: commands will be executed using /bin/sh
at> bash <<'EOF'
at> echo {1..5} >/tmp/output
at> EOF
at> <EOT>
job 24 at Mon Mar 23 20:41:20 2015
$ cat /tmp/output
1 2 3 4 5
<<word
声明一个此处文档,该文档作为标准输入提供bash
并持续到word
。通过引用'EOF'
该文件不会受到 shell 的扩展,因此您可以$
在正文中写入 a 而无需dash
吃掉它。您的脚本可以EOF
在行首包含除(或您选择的单词)以外的任何内容。
这确实是我推荐的方法——你几乎可以像你一直bash
在使用的那样来写它,只是在开头和结尾加上一行来显示发生了什么。
如果它真的只是一行,那么使用bash -c
传递单个命令来运行:
$ at now
warning: commands will be executed using /bin/sh
at> bash -c 'echo {1..3} >/tmp/output'
at> <EOT>
job 25 at Mon Mar 23 20:50:03 2015
$ cat /tmp/output
1 2 3
当您在命令中也使用引号时,这可能会有点麻烦。
最黑客的是:atd
通常将作业作为标准输入发送到外壳(但我不认为这是必需的)。 Shell 通常逐行读取标准输入(但不要求它们以这种方式运行)。
如果您的实现确实如此,那么您可以执行一个令人讨厌的技巧来在另一个 shell 下运行您的作业:
$ at now
warning: commands will be executed using /bin/sh
at> bash
at> echo {1..10} >/tmp/output
at> <EOT>
job 22 at Mon Mar 23 20:40:00 2015
$ cat /tmp/output
1 2 3 4 5 6 7 8 9 10
这是有效的,因为sh
读取第一行并执行bash
,bash
然后读取标准输入的其余部分作为其命令。这是非常脆弱的,但在工作时是侵入性最小的版本。
dash
它本身在这方面比许多 shell 更复杂,并且填充内部缓冲区对它来说更重要。其他简单的 shell,例如 BusyBox 的sh
,往往具有行缓冲行为。
最后,虽然你从来没有必需的使用单独的脚本文件,在许多情况下,它实际上是更好的选择,而不是试图把事情搞得太聪明。当您的作业是一次性使用或以编程方式生成时,这些都是合理的选择,但从维护角度来看,任何其他时候吸收它并使用独立脚本可能都是值得的。
我真的不建议使用最后一个选项的标准输入,但这是一个可爱的技巧。
答案2
到目前为止我找到的唯一解决方案是编写一个脚本(我们称之为expandme.sh),它指定使用bash
解释器。
#!/bin/bash
echo {1..10} >output
然后,从提示符处运行脚本at
:
$ at - now
warning: commands will be executed using /bin/sh
at> expandme.sh
at> <EOT>
现在,脚本将使我们脱离原来的dash
/ Bourne
exile 并在转储输出之前执行扩展。