在 bash 中,文件运算符 (-f) 可以不区分大小写吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3211076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In bash, can the file operator (-f) be case-insensitive?
提问by Paul Richter
I'm doing the following:
我正在做以下事情:
if [ -f $FILE ] ; then
echo "File exists"
fi
But I want the -fto be case-insensitive. That is, if FILE is /etc/somefile, I want -f to recognize /Etc/SomeFile.
但我希望-f不区分大小写。也就是说,如果 FILE 是/etc/somefile,我想要 -f 来识别/Etc/SomeFile.
I can partially work around it with glob:
我可以用 glob 部分解决它:
shopt -s nocaseglob
TARG='/etc/somefile'
MATCH=$TARG* #assume it returns only one match
if [[ -f $MATCH ]] ; then
echo "File exists"
fi
but the case-insensitive globbing works only on the filename portion, not the full path. So it won't work if TARG is /Etc/somefile.
但不区分大小写的通配符仅适用于文件名部分,而不适用于完整路径。所以如果 TARG 是/Etc/somefile.
Is there any way to do this?
有没有办法做到这一点?
回答by Borealid
The problem is that your filesystemis case-sensitive. The filesystem provides only two relevant ways to get a file: either you specify an exact, case-sensitive filename and check for its existence that way, or you read all the files in a directory and then check if each one matches a pattern.
问题是您的文件系统区分大小写。文件系统只提供了两种获取文件的相关方法:要么指定一个准确的、区分大小写的文件名并以这种方式检查它是否存在,要么读取目录中的所有文件,然后检查每个文件是否与模式匹配。
In other words, it is very inefficient to check if a case-insensitive version of a file exists on a case-sensitive filesystem. The shell might do it for you, but internally it's reading all the directory's contents and checking each one against a pattern.
换句话说,检查大小写敏感的文件系统上是否存在不区分大小写的文件版本是非常低效的。shell 可能会为你做这件事,但它在内部读取所有目录的内容并根据模式检查每个内容。
Given all that, this works:
鉴于所有这些,这有效:
if [[ -n $(find /etc -maxdepth 1 -iname passwd) ]]; then
echo "Found";
fi
BUT you unless you want to search everything from '/' on down, you must check component of the path individually. There is no way around this; you can't magically check a whole path for case-insensitive matches on a case-sensitive filesystem!
但是除非您想从“/”开始搜索所有内容,否则您必须单独检查路径的组成部分。没有办法解决这个问题;您无法在区分大小写的文件系统上神奇地检查整个路径以查找不区分大小写的匹配项!
回答by Jokester
not knowing howto only using shell evaluations. but grep can be case-insensitive, therefore a script that invokes grep , find and wc may meet your demand.
不知道如何只使用外壳评估。但是 grep 可以不区分大小写,因此调用 grep 、 find 和 wc 的脚本可能会满足您的需求。
回答by ghostdog74
you can use the nocasematch option
您可以使用 nocasematch 选项
shopt -s nocasematch
for file in *
do
case "$file" in
"/etc/passWd" ) echo $file;;
esac
done
回答by Philipp
This is very hard to do in general if the file system is case-insensitive. Basically you have do iterate over each of the ancestor directories separately. Here is a starting point in Python:
如果文件系统不区分大小写,这通常很难做到。基本上,您已经分别迭代了每个祖先目录。这是 Python 的起点:
import os
def exists_nocase(path):
if os.path.exists(path):
return True
path = os.path.normpath(os.path.realpath(os.path.abspath(unicode(path)))).upper()
parts = path.split(os.sep)
path = unicode(os.path.join(unicode(os.path.splitdrive(path)[0]), os.sep))
for name in parts:
if not name:
continue
# this is a naive and insane way to do case-insensitive string comparisons:
entries = dict((entry.upper(), entry) for entry in os.listdir(path))
if name in entries:
path = os.path.join(path, entries[name])
else:
return False
return True
print exists_nocase("/ETC/ANYTHING")
print exists_nocase("/ETC/PASSWD")
回答by carlo
cd /etc
# using FreeBSD find
find -x -L "$(pwd)" -maxdepth 1 -type f -iregex "/EtC/[^\/]*" -iname paSSwd
回答by juan
And here's a starting point using Bash:
这是使用 Bash 的起点:
# fci -- check if file_case_insensitive exists
# (on a case sensitive file system; complete file paths only!)
function fci() {
declare IFS checkdirs countslashes dirpath dirs dirstmp filepath fulldirpaths i name ndirs result resulttmp
[[ -f "" ]] && { return 0; }
[[ "${1:0:1}" != '/' ]] && { echo "No absolute file path given: " 2>&1; return 1; }
[[ "" == '/' ]] && { return 1; }
filepath=""
filepath="${filepath%"${filepath##*[!/]}"}" # remove trailing slashes, if any
dirpath="${filepath%/*}"
name="${filepath##*/}"
IFS='/'
dirs=( ${dirpath} )
if [[ ${#dirs[@]} -eq 0 ]]; then
fulldirpaths=( '/' )
ndirs=1
else
IFS=""
dirs=( ${dirs[@]} )
ndirs=${#dirs[@]}
for ((i=0; i < ${ndirs}; i++)); do
if [[ $i -eq 0 ]]; then
checkdirs=( '/' )
else
checkdirs=( "${dirstmp[@]}" )
fi
IFS=$'7'
dirstmp=( $( find -x -L "${checkdirs[@]}" -mindepth 1 -maxdepth 1 -type d -iname "${dirs[i]}" -print0 2>/dev/null | tr '##代码##' '7' ) )
IFS=""
fulldirpaths=( ${fulldirpaths[@]} ${dirstmp[@]} )
done
fi
printf "fulldirpaths: %s\n" "${fulldirpaths[@]}" | nl
for ((i=0; i < ${#fulldirpaths[@]}; i++)); do
countslashes="${fulldirpaths[i]//[^\/]/}"
[[ ${#countslashes} -ne ${ndirs} ]] && continue
IFS=$'7'
resulttmp=( $( find -x -L "${fulldirpaths[i]}" -mindepth 1 -maxdepth 1 -type f -iname "${name}" -print0 2>/dev/null | tr '##代码##' '7' ) )
IFS=""
result=( ${result[@]} ${resulttmp[@]} )
done
IFS=""
result=( ${result[@]} )
printf "result: %s\n" "${result[@]}" | nl
if [[ ${#result[@]} -eq 0 ]]; then
return 1
else
return 0
fi
}
FILE='/eTC/paSSwD'
if fci "${FILE}" ; then
echo "File (case insensitive) exists: ${FILE}"
else
echo "File (case insensitive) does NOT exist: ${FILE}"
fi

