найти в каталоге, который начинается с тире - PullRequest
10 голосов
/ 26 ноября 2010

find интерпретирует дефис в начале имени файла как начало опции. Использование знакомого -- трюка не работает, так как опции идут после имени файла, цитирование не имеет никакого эффекта, и замена первого тире на \- также не работает Пользователям часто рекомендуется ставить перед такими именами файлов ./, но что мне делать, если я не знаю, будет ли данный путь абсолютным или относительным?

Редактировать: Одним из решений является find "$(readlink -f -- "$test_filename")", но это ужасно. Есть идеи получше?

Редактировать 2 : Спасибо за предложения. Вот два сценария, которые возникли в результате этих усилий: safe-find.sh ; safe-count-files.sh

Ответы [ 4 ]

6 голосов
/ 26 ноября 2010

Если это в сценарии, вы всегда можете проверить это. Например. для bash, ksh или zsh:

if [[ "$DIR" = -* ]]; then
    find ./"$DIR"
else
    find "$DIR"
fi

В более краткой форме (для bash, ksh93 или zsh):

find "${DIR/#-/./-}"

Вы можете даже сделать это с параметрами скрипта, если они все должны быть каталогами:

find "${@/#-/./-}"
5 голосов
/ 26 ноября 2010

Это может показаться немного дешевым, но я на самом деле рекомендую обходной путь readlink, который вы нашли.Согласно стандарту Unix ,

Первый аргумент, начинающийся с '-' (...), и все последующие аргументы должны интерпретироваться как выражение

, поэтому -- действительно не будет работать.Решение thkala также может работать, но я считаю его менее читабельным.Хотя это может быть быстрее, если вы выполняете много вызовов find.

3 голосов
/ 27 ноября 2010

Вот способ, который должен работать на всех Unix-подобных системах, без требования к конкретной оболочке или нестандартной утилите¹.

case $DIR in
  -*) DIR=./$DIR;;
esac
find "$DIR" …

Если у вас есть список каталогов в ваших позиционных параметрах и вы хотите их обработать, это немного усложняется. Вот решение POSIX sh:

i=1
while [ $i -le $# ]; do
  case $1 in
    -*) x=./$1;;
    *) x=$1;;
  esac
  set -- "$@" "$x"
  shift
  i=$(($i + 1))
done
find "$@" …

Оболочкам Борна и другим реализациям до POSIX sh не хватает арифметики и set --, так что это немного уродливее.

i=1
while [ $i -le $# ]; do
  x=$1
  case $1 in
    -*) x=./$1;;
  esac
  set a "$@" "$x"
  shift
  shift
  i=`expr $i + 1`
done
find "$@" …

¹ readlink -f доступно в GNU (Linux, Cygwin и т. Д.), NetBSD ≥4.0, OpenBSD ≥2.2, BusyBox. Он недоступен (если только вы не установили инструменты GNU и не убедились, что они включены в PATH) в Mac OS X (по состоянию на 10.6.4), HP-UX (по состоянию на 11.22), Solaris (по состоянию на OpenSolaris 200906), AIX (по состоянию на 7.1).

0 голосов
/ 26 ноября 2010

Используйте шарик, чтобы захватить тире:

find . -name '[-]*'

edit: обновлено, чтобы удалить регулярное выражение фразы и заключить в кавычки глобус, чтобы он интерпретировался как find, а не bash (влияет только на некоторые крайние случаи).

...