根据我收集的信息,您想在使用时检查一下
tee -- "$OUT_FILE"
(请注意,--
或否则不适用于以-开头的文件名),tee
将成功打开文件进行写入。
就这样:
- 文件路径的长度不超过PATH_MAX的限制
- 该文件存在(在符号链接解析之后),并且不是目录类型,并且您具有对该文件的写许可权。
- 如果该文件不存在,则该文件的目录名作为目录存在(在符号链接解析之后),并且您对该文件具有写和搜索权限,并且文件名长度不超过该目录所位于的文件系统的NAME_MAX限制。
- 或文件是一个符号链接,指向一个不存在的文件,它不是一个符号链接循环,但符合上面的条件
现在,我们将忽略像vfat,ntfs或hfsplus这样的文件系统,这些文件系统对文件名可能包含的字节值,磁盘配额,进程限制,selinux,apparmor或其他安全机制有限制,例如完整的文件系统,没有索引节点,设备由于某种原因而无法通过这种方式打开的文件,即当前在某个进程地址空间中映射的可执行文件,所有这些文件也可能影响打开或创建文件的能力。
与zsh
:
zmodload zsh/system
tee_would_likely_succeed() {
local file=$1 ERRNO=0 LC_ALL=C
if [ -d "$file" ]; then
return 1 # directory
elif [ -w "$file" ]; then
return 0 # writable non-directory
elif [ -e "$file" ]; then
return 1 # exists, non-writable
elif [ "$errnos[ERRNO]" != ENOENT ]; then
return 1 # only ENOENT error can be recovered
else
local dir=$file:P:h base=$file:t
[ -d "$dir" ] && # directory
[ -w "$dir" ] && # writable
[ -x "$dir" ] && # and searchable
(($#base <= $(getconf -- NAME_MAX "$dir")))
return
fi
}
在bash
任何类似Bourne的外壳中,只需更换
zmodload zsh/system
tee_would_likely_succeed() {
<zsh-code>
}
与:
tee_would_likely_succeed() {
zsh -s -- "$@" << 'EOF'
zmodload zsh/system
<zsh-code>
EOF
}
zsh
这里的-specific功能是$ERRNO
(公开最后一个系统调用的错误代码)和$errnos[]
关联数组,以转换为相应的标准C宏名称。和$var:h
(来自csh)和$var:P
(需要zsh 5.3或更高版本)。
bash还没有等效功能。
$file:h
可以用dir=$(dirname -- "$file"; echo .); dir=${dir%??}
或用GNU 代替dirname
:IFS= read -rd '' dir < <(dirname -z -- "$file")
。
对于$errnos[ERRNO] == ENOENT
,一种方法是ls -Ld
在文件上运行,并检查错误消息是否对应于ENOENT错误。但是,可靠且便携地执行此操作很棘手。
一种方法可能是:
msg_for_ENOENT=$(LC_ALL=C ls -d -- '/no such file' 2>&1)
msg_for_ENOENT=${msg_for_ENOENT##*:}
(假设错误消息以的翻译结尾syserror()
,ENOENT
并且该翻译不包含:
),然后代替[ -e "$file" ]
:
err=$(ls -Ld -- "$file" 2>&1)
并检查是否有ENOENT错误
case $err in
(*:"$msg_for_ENOENT") ...
esac
该$file:P
部分是在中最难实现的bash
,尤其是在FreeBSD上。
FreeBSD确实有一个realpath
命令和一个readlink
接受-f
选项的命令,但是在文件是无法解析的符号链接的情况下不能使用它们。这是具有相同perl
的Cwd::realpath()
。
python
的os.path.realpath()
确实出现了类似的工作zsh
$file:P
,所以假设中的至少一个版本python
已安装并有一个python
引用其中之一(这是不是在FreeBSD给出),你可以做的命令:
dir=$(python -c '
import os, sys
print(os.path.realpath(sys.argv[1]) + ".")' "$dir") || return
dir=${dir%.}
但是,您也可以在中完成整个操作python
。
或者,您可以决定不处理所有这些极端情况。