文件描述符
有人能告诉我为什么这不起作用吗? 我正在玩文件描述符,但感觉有点失落。
#!/bin/bash echo "This" echo "is" >&2 echo "a" >&3 echo "test." >&4
前三行运行良好,但最后两个错误。 为什么? 谢谢您的帮助!
文件描述符0,1和2分别用于stdin,stdout和stderr。
文件描述符3,4,… 9用于附加文件。 为了使用它们,您需要先打开它们。 例如:
exec 3<> /tmp/foo #open fd 3. echo "test" >&3 exec 3>&- #close fd 3.
有关更多信息,请参阅高级Bash脚本指南:第20章I / Oredirect 。
这是一个古老的问题,但有一件事需要澄清 。
虽然卡尔诺鲁姆和dogbane的答案是正确的,假设是改变你的脚本,使其工作 。
我想指出的是, 你不需要改变脚本 :
#!/bin/bash echo "This" echo "is" >&2 echo "a" >&3 echo "test." >&4
如果以不同的方式调用它,它将起作用:
./fdtest 3>&1 4>&1
这意味着将文件描述符3和4redirect到1(这是标准输出)。
重点在于, 如果这些描述符是由父进程提供的 , 那么脚本完全可以写入除1和2以外的描述符(stdout和stderr)。
你的例子其实很有趣,因为这个脚本可以写入4个不同的文件:
./fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
现在你有4个单独的文件输出:
$ for f in file*; do echo $f:; cat $f; done file1.txt: This file2.txt: is file3.txt: a file4.txt: test.
更有意思的是,你的程序不必为这些文件拥有写权限,因为它实际上并没有打开它们。
例如,当我运行sudo -s
将用户更改为root用户时,以root用户身份创build一个目录,并尝试以普通用户身份运行以下命令(在我的情况下为rsp),如下所示:
# su rsp -c '../fdtest >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt'
我收到一个错误:
bash: file1.txt: Permission denied
但是如果我在su
之外进行redirect,
# su rsp -c '../fdtest' >file1.txt 2>file2.txt 3>file3.txt 4>file4.txt
(注意单引号的区别) 它的工作原理和我得到:
# ls -alp total 56 drwxr-xr-x 2 root root 4096 Jun 23 15:05 ./ drwxrwxr-x 3 rsp rsp 4096 Jun 23 15:01 ../ -rw-r--r-- 1 root root 5 Jun 23 15:05 file1.txt -rw-r--r-- 1 root root 39 Jun 23 15:05 file2.txt -rw-r--r-- 1 root root 2 Jun 23 15:05 file3.txt -rw-r--r-- 1 root root 6 Jun 23 15:05 file4.txt
即root拥有的根目录中拥有的4个文件 – 即使该脚本没有创build这些文件的权限 。
另一个例子是使用chroot jail或者一个容器,然后在内部运行一个程序,即使它以root身份运行,仍然无法访问这些文件,并且仍然在需要时从外部redirect这些描述符,而无法实际访问整个文件系统或其他任何东西到这个脚本。
关键是你已经发现了一个非常有趣和有用的机制 。 您不必像其他答案中所build议的那样打开脚本中的所有文件。 有时在脚本调用期间redirect它们是有用的。
总结起来 ,这个:
echo "This"
其实相当于:
echo "This" >&1
并运行该程序为:
./program >file.txt
是相同的:
./program 1>file.txt
数字1只是一个默认的数字,它是标准输出。
但即使这个程序:
#!/bin/bash echo "This"
可能会产生“错误的描述符”错误。 怎么样? 当运行时:
./fdtest2 >&-
输出将是:
./fdtest2: line 2: echo: write error: Bad file descriptor
添加>&-
(与1>&-
相同)意味着closures标准输出。 添加2>&-
将意味着closuresstderr。
你甚至可以做一个更复杂的事情 。 您的原始脚本:
#!/bin/bash echo "This" echo "is" >&2 echo "a" >&3 echo "test." >&4
当运行只是:
./fdtest
打印:
This is ./fdtest: line 4: 3: Bad file descriptor ./fdtest: line 5: 4: Bad file descriptor
但是你可以使描述符3和4工作,但是1号运行失败:
./fdtest 3>&1 4>&1 1>&-
它输出:
./fdtest: line 2: echo: write error: Bad file descriptor is a test.
如果你想要描述符1和2都失败,就像这样运行它:
./fdtest 3>&1 4>&1 1>&- 2>&-
你得到:
a test.
为什么? 没有任何失败? 它做了,但没有标准错误(文件描述符编号2), 你没有看到错误信息!
我认为这样做是非常有用的,以便了解描述符及其redirect如何工作。
你的脚本确实是一个非常有趣的例子 – 我认为它并没有被打破,你只是错误地使用它! 🙂
这是失败的,因为这些文件描述符不指向任何东西! 正常的默认文件描述符是标准input0
,标准输出1
和标准错误stream2
。 由于您的脚本不打开任何其他文件,因此没有其他有效的文件描述符。 你可以使用exec
在bash中打开一个文件。 这是你的例子的一个修改:
#!/bin/bash exec 3> out1 # open file 'out1' for writing, assign to fd 3 exec 4> out2 # open file 'out2' for writing, assign to fd 4 echo "This" # output to fd 1 (stdout) echo "is" >&2 # output to fd 2 (stderr) echo "a" >&3 # output to fd 3 echo "test." >&4 # output to fd 4
现在我们将运行它:
$ ls script $ ./script This is $ ls out1 out2 script $ cat out* a test. $
正如你所看到的,额外的输出被发送到请求的文件。