“2<&1”是什么意思在 Bourne shell 中重定向做什么?

发布于 2025-01-06 21:13:37 字数 496 浏览 0 评论 0 原文

Bourne shell 中的 2>&1 重定向将发送到文件描述符 2 的输出(默认情况下为标准错误)发送到文件描述符 1(默认情况下为标准输出)。

但是 2<&1 重定向有什么作用呢?

它会将 stderr 发送到 stdin 吗?

我的理论是,它将 stdin 发送到 stderr (例如与 1>&2 相同),但实验上情况并非如此:

$ perl -e 'print "OUT\n"; print STDERR "ERR\n"; \
  while (<>) { print "IN WAS $_\n";}'           \
  > out3 2<&1
df
$ cat out3
ERR
OUT
IN WAS df

请注意,标准输出和标准错误都发送到文件 out3,其中 stdout被重定向。

2>&1 redirect in Bourne shell takes the output sent to a file descriptor 2 (by default, standard error) and sends it instead to file descriptor 1 (by default a standard output).

But what does 2<&1 redirect do?

Does it send stderr to stdin?

My theory was that it was sending stdin to stderr (e.g. same as 1>&2) but experimentally, that is NOT the case:

$ perl -e 'print "OUT\n"; print STDERR "ERR\n"; \
  while (<>) { print "IN WAS $_\n";}'           \
  > out3 2<&1
df
$ cat out3
ERR
OUT
IN WAS df

Note that standard out AND standard error both went to file out3 where stdout was redirected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜唯美灬不弃 2025-01-13 21:13:37

<& 运算符复制“输入”文件描述符。根据 IEEE Std 1003.1-2001(又名单一 Unix 规范 v3,POSIX 的后继者),如果 1 不是打开输入的文件描述符,则 2<&1 应该是错误的。但是,bash 似乎很懒,并且不关心文件描述符是否打开以供输入或输出。

因此 2<&12>&1 都只是执行系统调用 dup2(1, 2),该调用复制文件描述符1 到文件描述符 2。

您可以通过运行这样的命令进行检查,因为重定向是从左到右执行的:

sleep 99999 1>/dev/null 2<&1

然后在另一个窗口中,在 sleep 上运行 lsof过程。您将看到文件描述符 1 和 2 都指向 /dev/null。示例(在我的 Mac 上):

:; ps axww | grep sleep
 8871 s001  R+     0:00.01 grep sleep
 8869 s003  S+     0:00.01 sleep 99999
:; lsof -p 8869 | tail -2
sleep   8869 mayoff    1w   CHR    3,2       0t0       316 /dev/null
sleep   8869 mayoff    2w   CHR    3,2       0t0       316 /dev/null

The <& operator duplicates an “input” file descriptor. According to IEEE Std 1003.1-2001 (aka Single Unix Specification v3, the successor to POSIX), it's supposed to be an error to say 2<&1 if 1 is not a file descriptor open for input. However, it appears that bash is lazy and doesn't care if the file descriptor is open for input or for output.

So both 2<&1 and 2>&1 simply perform the system call dup2(1, 2), which copies file descriptor 1 to file descriptor 2.

You can check by running a command like this, since redirections are performed left-to-right:

sleep 99999 1>/dev/null 2<&1

Then in another window, run lsof on the sleep process. You'll see that both file descriptors 1 and 2 point to /dev/null. Example (on my Mac):

:; ps axww | grep sleep
 8871 s001  R+     0:00.01 grep sleep
 8869 s003  S+     0:00.01 sleep 99999
:; lsof -p 8869 | tail -2
sleep   8869 mayoff    1w   CHR    3,2       0t0       316 /dev/null
sleep   8869 mayoff    2w   CHR    3,2       0t0       316 /dev/null
云柯 2025-01-13 21:13:37

查看 Bash 源代码中的解析器代码,似乎 2>&1 的处理方式与 2<&1 相同。

parse.y

|   NUMBER LESS_AND NUMBER
        {
          redir.dest = $3;
          $ = make_redirection ($1, r_duplicating_input, redir);
        }
...
|   NUMBER GREATER_AND NUMBER
        {
          redir.dest = $3;
          $ = make_redirection ($1, r_duplicating_output, redir);
        }

查看重定向源redir.c,常量r_duplicating_inputr_duplicating_output似乎被处理为同样的方式。与 make_cmd.c 中的 make_redirection 函数相同。

使用一个简单的程序进行测试,该程序将“yay”打印到stdout,将“nay”打印到stderr,我可以确认您的测试结果:

$ ./a.out > out 2>&1
$ cat out
nay
yay
$ ./a.out > out 2<&1
$ cat out
nay
yay
$ ./a.out > out 1>&2
yay
nay
$ cat out
$ ./a.out > out 1<&2
yay
nay
$ cat out
$

Looking at the parser code in the source for Bash, it seems that 2>&1 is treated in the same way as 2<&1.

parse.y

|   NUMBER LESS_AND NUMBER
        {
          redir.dest = $3;
          $ = make_redirection ($1, r_duplicating_input, redir);
        }
...
|   NUMBER GREATER_AND NUMBER
        {
          redir.dest = $3;
          $ = make_redirection ($1, r_duplicating_output, redir);
        }

Looking through the redirection source redir.c, the constants r_duplicating_input and r_duplicating_output seem to be treated in the same way. Same as in the make_redirection function in make_cmd.c.

Testing with a simple program that prints "yay" to stdout and "nay" to stderr, I can confirm your test results:

$ ./a.out > out 2>&1
$ cat out
nay
yay
$ ./a.out > out 2<&1
$ cat out
nay
yay
$ ./a.out > out 1>&2
yay
nay
$ cat out
$ ./a.out > out 1<&2
yay
nay
$ cat out
$
错爱 2025-01-13 21:13:37

来自 REDIRECTION 下的 man bash

   Duplicating File Descriptors
       The redirection operator

              [n]<&word

       is used to duplicate input  file  descriptors.   If  word
       expands  to  one  or  more  digits,  the  file descriptor
       denoted by n is made to be a copy of that  file  descrip‐
       tor.   If  the  digits  in  word  do  not  specify a file
       descriptor open for input, a  redirection  error  occurs.
       If  word evaluates to -, file descriptor n is closed.  If
       n is not specified, the standard input  (file  descriptor
       0) is used.

因此,在 2<&1 的情况下,似乎 2 ( stderr)被制作为1stdout)的副本。我用 1<&2 的另一种方式对其进行了测试,使 stdout 成为 stderr 的副本。

因此,在测试程序中:

#!/bin/bash
echo hello 1<&2

在命令行上运行时, hello 输出到 stderr 而不是 stdout

$ ./test > /dev/null
hello
$ ./test > /dev/null 2>&1
$ 

From man bash under REDIRECTION:

   Duplicating File Descriptors
       The redirection operator

              [n]<&word

       is used to duplicate input  file  descriptors.   If  word
       expands  to  one  or  more  digits,  the  file descriptor
       denoted by n is made to be a copy of that  file  descrip‐
       tor.   If  the  digits  in  word  do  not  specify a file
       descriptor open for input, a  redirection  error  occurs.
       If  word evaluates to -, file descriptor n is closed.  If
       n is not specified, the standard input  (file  descriptor
       0) is used.

So in the case of 2<&1, it seems that 2 (stderr) is made to be a copy of 1 (stdout). I've tested it with the other way around 1<&2 makes stdout to be a copy of stderr.

So in a test program:

#!/bin/bash
echo hello 1<&2

When run on command line, hello is output to stderr not stdout

$ ./test > /dev/null
hello
$ ./test > /dev/null 2>&1
$ 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文