我想让 bash 脚本在打开时向大于或等于 3 的文件描述符 (FD) 输出附加信息。为了测试 FD 是否打开,我设计了以下技巧:
if (printf '' 1>&3) 2>&-; then
# File descriptor 3 is open
else
# File descriptor 3 is not open
fi
这足以满足我的需求,但我很好奇是否有更惯用的方法来测试 FD 是否有效。我特别感兴趣的是是否存在系统调用到 shell 命令的映射fcntl(1)
,这将允许检索 FD 标志(O_WRONLY
并 O_RDWR
测试 FD 是否可写,并O_RDONLY
测试 O_RDWR
FD 是否可读)。
答案1
在ksh
(AT&T 和 pdksh 变体)或中zsh
,您可以执行以下操作:
if print -nu3; then
echo fd 3 is writeable
fi
他们不会在该 fd 上写入任何内容,但仍然检查该 fd 是否可写(使用fcntl(3, F_GETFL)
),否则报告错误:
$ ksh -c 'print -nu3' 3< /dev/null
ksh: print: -u: 3: fd not open for writing
(您可以重定向到/dev/null
)。
对于bash
,我认为您唯一的选择是检查 a 是否dup()
像您的方法一样成功,尽管这不能保证 fd 可写(或调用外部实用程序(zsh
/ perl
...)来执行fcntl()
)。
请注意,在bash
(像大多数 shell 一样)中,如果您使用(...)
代替{...;}
,则会分叉一个额外的进程。您可以使用:
if { true >&3; } 2> /dev/null
而是为了避免分叉(除了在 Bourne shell 中,重定向复合命令总是会导致子 shell)。不要使用:
代替,true
因为那是特别的内置的,因此当 bash 处于 POSIX 合规模式时会导致 shell 退出。
但是,您可以将其缩短为:
if { >&3; } 2> /dev/null
答案2
在 POSIX 中command
应用程序使用描述你会发现以下内容:
有时抑制特殊内置函数的特殊特性有一些优点。例如:
command exec > unwritable-file
不会导致非交互式脚本中止,因此可以通过脚本检查输出状态。
这就是为什么你可以这样做:
if command >&3
then echo 3 is open >&3
else ! echo 3 is not open
fi 2<>/dev/null
或者...
{ command >&3
printf %s\\n%.0d string "0$(($??8:0))" >&"$(($??1:3))"
} 2<>/dev/null
哪个会写细绳后跟一个\n
ewline 到 stdout 或 3,并且当 3 未打开时仍然传递非零退出状态,因为完成的数学$?
最终无法转换八进制08到%十进制但将八进制截断为空00。
或者...
command exec >&3 || handle_it
但如果你正在使用ksh93
,你可以这样做:
fds
用于打开文件描述符的列表。添加-l
以查看它们去了哪里。
答案3
打开的文件描述符可以在 中找到/proc/<pid>/fd
。例如,要列出当前 shell 的打开文件描述符,您可以发出ls -l /proc/$$/fd
如下命令:
total 0
lrwx------ 1 testuser testuser 64 jun 1 09:11 0 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun 1 09:11 1 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun 1 09:11 2 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun 1 09:39 255 -> /dev/pts/3
当您使用以下命令打开文件时:
touch /tmp/myfile
exec 7</tmp/myfile
它应该由新的列出ls -l /proc/$$/fd
:
lr-x------ 1 testuser testuser 64 jun 1 09:11 7 -> /tmp/myfile
如果您再次使用它关闭文件描述符,exec 7>&-
它也不再列出/proc/$$/fd
。
答案4
这个问题很老了 - 但无论如何 - 为什么不使用内置函数?
for i in {0..5} ; do if [ -t $i ]; then echo "$i is a valid FD"; else echo "$i is INVALID FD"; fi; done
输出:
0 is a valid FD
1 is a valid FD
2 is a valid FD
3 is INVALID FD
4 is INVALID FD
5 is INVALID FD
因此,回答这个问题 - 建议:
if [ -t 3 ]; then
# File descriptor 3 is open
else
# File descriptor 3 is not open
fi