无法访问2>&1:如何将变量内容视为重定向而不是文件名

4

我如何根据变量内容控制进程输出重定向? 我尝试了以下代码,但它把$redirect的内容视为文件名而不是重定向。

$ redirect="2>&1 >/dev/null"
$ ls -la $redirect
ls: cannot access 2>&1: No such file or directory
$ redirect=""
$ ls -la $redirect
total 376
drwx------ 1 wakatana users   4096 Feb  5 15:32 .
drwx------ 1 wakatana users   4096 Feb  2 18:44 ..
-rw------- 1 wakatana users    390 Feb  5 13:34 .bashrc

1
你不能像这样做。评估的顺序不会按照那种方式工作。你可以使用eval来强制执行,但你不想那样做。这不安全也不是一个好主意。 - Etan Reisner
4
当Bash扩展变量redirect时,所有的操作符都已经被扫描过了。可以参考Bash如何处理读入内容。因此,在这里,2>&1不会被解释为重定向操作符,而只是作为一个简单的参数。请注意,本文不包括解释。 - gniourf_gniourf
1
请注意Code Frenzy所提到的内容。您需要将stderr重定向到指向stdout指向的位置,然后将stdout重定向到/dev/null。这不会将stderr重定向到/dev/null!它是从左到右按顺序解释的。 - Jite
3个回答

4
这里有一个实现你想要的方法,但前提是你接受改变命令的顺序:使用别名。虽然别名通常不被赞同,正如Bash手册所述,“几乎每个目的都可以通过shell函数来取代别名。”似乎我们在这里已经违反了“几乎”这个限制。
$ alias redirect='2>&1 > /dev/null'
$ redirect ls
$

并且不允许使用eval


根据OP的评论,重定向顺序被倒置。 - Etan Reisner
@EtanReisner,我没有看到OP提到他想将stdout重定向到“/dev/null”,并将stderr重定向到终端。 - gniourf_gniourf
你说得完全正确,他没有这样做,但是这种重定向大多数情况下都是错误的(尤其是对于不熟悉 shell 的人)。另外,你说“(没有输出,一切都被重定向到 /dev/null )”,这并不是它的作用。=) - Etan Reisner
@EtanReisner 是的,我把那部分搞砸了! - gniourf_gniourf
@rici:你的函数在子shell中执行命令。如果我们正在重定向具有副作用(例如设置变量)的函数的输出,则可能不需要此功能。然后 redirect() { 2>&1 > /dev/null "$@"; } 当然可以工作,但是当我编写这个时,我考虑尽可能保留OP的语法。在这种情况下,定义别名比定义函数更容易(可以说),特别是如果OP经常想修改 redirect - gniourf_gniourf
显示剩余3条评论

3
“ls”错误发生是因为Shell在执行参数扩展之前(还考虑重定向序列)扫描重定向,尝试列出名为“2> & 1”和“> / dev / null”的两个文件,就像您键入“ls'2> & 1''> / dev / null'”一样。实现你想要的目的的方法是进行第二次迭代所有重定向和替换。内置命令“eval”正是做到这一点的方式:
 eval ls -la $redirect

如果你想了解,根据POSIX shell规范,顺序如下:
  1. 根据Shell语法规则识别为变量赋值或重定向的单词将保存以供步骤3和4处理。

  2. 对不是变量赋值或重定向的单词进行扩展。如果它们的扩展后仍有字段,则第一个字段将被视为命令名称,其余字段是命令的参数。

  3. 按照Redirection中所述执行重定向。

  4. 在分配值之前,应对每个变量赋值进行tilde扩展、参数扩展、命令替换、算术扩展和引号删除。

以下是一个较简单的重定向示例,用于说明正在发生的情况:

$ redirect=">file"
$ echo foo $redirect
foo >file
$ eval echo foo $redirect
$ cat file
foo

正如Etan所指出的那样,如果您无法控制redirect的确切内容,则eval可能不是一个合适的解决方案。 想象一下redirect='; rm -rf $HOME'可以做什么。


Bash 在参数替换之前不执行参数替换。请参见此链接:第4点(扩展)出现在第5点之前。您实际上可以进行实验:set -u; echo "$a" > test:如果未设置变量a,则不会创建文件test。 - gniourf_gniourf
1
@gniourf_gniourf 感谢您指出这一点。我已经相应地修改了措辞,并用“扫描重定向”替换了“执行重定向”,希望更接近 POSIX 步骤 1 的要求。 - Jens

1

需要将 2>&1 的顺序反转,更改为:

$redirect="2>&1 >/dev/null"

$redirect=">/dev/null 2>&1"

编辑:

在命令行上运行ls -al,更好的选择是执行以下操作:

$redirect="ls -al >/dev/null 2>&1"
eval $redirect

在最后加入2>&1的目的是为了重定向由命令和第一个重定向产生的所有错误。

1
这完全没有回答问题。 - gniourf_gniourf
你测试过你写的代码了吗? - Jens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接