В bash может ли файловый оператор (-f) быть без учета регистра? - PullRequest
7 голосов
/ 09 июля 2010

Я делаю следующее:

if [ -f $FILE ] ; then
    echo "File exists"
fi

Но я хочу, чтобы -f не учитывал регистр. То есть, если FILE равен /etc/somefile, я хочу, чтобы -f распознал /Etc/SomeFile.

Я могу частично обойти это с помощью glob:

shopt -s nocaseglob
TARG='/etc/somefile'

MATCH=$TARG*    #assume it returns only one match

if [[ -f $MATCH ]] ; then
    echo "File exists" 
fi

, но регистронезависимое глобирование работает только с частью имени файла, а не с полным путем Так что это не будет работать, если TARG /Etc/somefile.

Есть ли способ сделать это?

Ответы [ 6 ]

10 голосов
/ 09 июля 2010

Проблема в том, что ваша файловая система чувствительна к регистру.Файловая система предоставляет только два соответствующих способа получения файла: либо вы указываете точное, чувствительное к регистру имя файла и проверяете его существование таким образом, либо читаете все файлы в каталоге и затем проверяете, соответствует ли каждый из них шаблону.

Другими словами, очень неэффективно проверять, существует ли нечувствительная к регистру версия файла в чувствительной к регистру файловой системе.Оболочка может сделать это для вас, но внутренне она читает все содержимое каталога и проверяет каждый из них по шаблону.

Учитывая все это, это работает:

if [[ -n `find /etc -maxdepth 1 -iname passwd` ]]; 
    then echo "Found";
fi

НО вас, если только выЧтобы искать все, начиная с '/' и далее, вы должны проверить компонент пути индивидуально.Обойти это невозможно;вы не можете волшебным образом проверить весь путь на наличие регистрозависимых совпадений в чувствительной к регистру файловой системе!

1 голос
/ 09 июля 2010

не зная, как использовать только оценки оболочки.но grep может не учитывать регистр, поэтому скрипт, который вызывает grep, find и wc, может удовлетворить ваши требования.

0 голосов
/ 15 июля 2010

А вот отправная точка с использованием 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 "$1" ]] && { return 0; }
[[ "${1:0:1}" != '/' ]] && { echo "No absolute file path given: ${1}" 2>&1; return 1; }
[[ "$1" == '/' ]] && { return 1; }

filepath="$1"
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=$'\777'
      dirstmp=( $( find -x -L "${checkdirs[@]}" -mindepth 1 -maxdepth 1 -type d -iname "${dirs[i]}" -print0 2>/dev/null | tr '\0' '\777' ) )

      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=$'\777'
   resulttmp=( $( find -x -L "${fulldirpaths[i]}" -mindepth 1 -maxdepth 1 -type f -iname "${name}" -print0 2>/dev/null | tr '\0' '\777' ) )
   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
0 голосов
/ 10 июля 2010
cd /etc
# using FreeBSD find
find -x -L "$(pwd)" -maxdepth 1 -type f -iregex "/EtC/[^\/]*" -iname paSSwd 
0 голосов
/ 09 июля 2010

В общем, это очень трудно сделать, если в файловой системе не учитывается регистр.По сути, вы делаете итерацию по каждому из каталогов предков в отдельности.Вот отправная точка в 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")
0 голосов
/ 09 июля 2010

вы можете использовать опцию nocasematch

shopt -s nocasematch
for file in *
do
  case "$file" in
   "/etc/passWd" ) echo $file;;
  esac
done 
...