基于这个答案,我编写了以下内容来交换文件描述符 1 和 2:
swap12
:
#!/bin/bash
"$@" 3>&1 1>&2 2>&3 3>&-
然后我可以在管道中对 STDERR 进行操作,例如:
$ swap12 ls -ld /tmp /ooooooo | tr o X
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 19 root root 1400 Jul 1 17:14 /tmp
然而,多次交换 FD 并不起作用:
$ swap12 ls -ld /tmp /ooooooo | swap12 tr o X | tr o Z
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 19 root root 1400 Jul 1 17:14 /tmp
上面我期望第二个swap12
再次交换 STDOUT 和 STDRR,因此第二个将在的原始 STDOUTtr
上运行。ls
我期待看到:
$ swap12 ls -ld /tmp /ooooooo | swap12 tr o X | tr o Z
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 19 rZZt rZZt 1400 Jul 1 17:14 /tmp
我怎样才能实现我所追求的目标?
我感觉我的问题是由于更改子 shell 中的文件描述符造成的。作为zsh
全局别名实施会有优势吗alias -g
? (但是bash
实施起来会是什么样子呢?)
答案1
通常情况下,stderr
直接进入终端,stdout
进入管道:
ls stdout -->
ls -ld /tmp /ooooooo | tr o X
|
v ls stderr (to terminal)
交换它们后,stdout
转到终端,而不是管道:
ls stderr -->
swap12 ls -ld /tmp /ooooooo | tr o X
|
v ls stdout
交换stdout
/不以任何方式涉及结果,stderr
因为它之前已从管道重定向。tr
stderr
ls
ls stderr --> tr stderr -->
swap12 ls -ld /tmp /ooooooo | swap12 tr o X | tr o Z
| |
v ls stdout v tr stdout
如果你想单独处理stdout
and stderr
of ls
,你可以使用进程替换(应该在 Bash 和 Zsh 中工作):
$ ls -ld /tmp /ooooooo 2> >(tr o X) > >(tr o Z)
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 25 rZZt rZZt 4096 Jul 1 14:40 /tmp/
答案2
管道已连接ls.stderr
至tr1.stdin
。然后交换tr1.stdout
andtr1.stderr
并通过管道连接tr1.stderr
到tr2.stdin
tr2 发现没有o
s,所以什么也不做。
第二个swap12
不应该也不会撤销第一个。
你打算这样做吗./swap12 ./swap12 ls -ld /tmp /ooooooo | tr o X
?这将撤消交换。