BASH - Как использовать find с $ @, когда $ @ содержит несуществующий файл? - PullRequest
0 голосов
/ 27 июня 2018

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

function SomeFunction () {
  # get list of files recursively
  fList=$(find $@ -type f) 
  do something with $fList
  .
  .
  .
}

[~]$SomeFunction existentFile nonexistentFile existentNonEmptyDir
find: `nonexistentFile': No such file or directory

fList=$(find $@ -type f) будет отлично работать, если бы не nonexistentFile. Есть ли способ сделать такой же вызов даже с отсутствующим файлом?

Ответы [ 2 ]

0 голосов
/ 27 июня 2018
someFunction () {
    # remove nonexistent names from argument list
    for pathname do
        [ -e "$pathname" ] && set -- "$@" "$pathname"
        shift
    done

    # exit with failure if none of the given pathnames existed
    [ "$#" -eq 0 ] && return 1

    # find regular files in the given existing paths and process these
    find "$@" -type f -exec sh -c '
        for pathname do
            # process found regular file "$pathname"
        done' sh {} +
}
  • Двойная кавычка $@, или оболочка выполнит разбиение слов и перетаскивание имен файлов по элементам.
  • Не сохраняйте вывод find в строку. Это сломалось бы, если бы любое имя файла содержало пробел.
0 голосов
/ 27 июня 2018

Вполне разумно просто игнорировать предупреждение от find. Однако, если вы хотите отфильтровать список аргументов для вещей, которые действительно существуют до его вызова, вы можете сделать это явно:

SomeFunction() {
  local -a existing_args=( )
  for arg in "$@"; do
    [[ -e "$arg" ]] && existing_args+=( "$arg" )
  done
  while IFS= read -r -d '' result; do
    printf 'Processing result: %q\n'  ## put your own code here
  done < <(find "${existing_args[@]}" -type f -print0)
}

Некоторые примечания:

  • Ключевое слово function взято из синтаксиса объявления функции ksh function SomeFunction {; Парены после имени функции берутся из синтаксиса объявления функции POSIX sh SomeFunction() {. Объединение их обоих дает результат, который не совместим ни с устаревшими ksh, ни с POSIX sh. См. http://wiki.bash -hackers.org / scripting / устарел
  • Цитирование "$@" обеспечивает правильную обработку имен файлов с пробелами, символами глобуса и т. Д .; аналогично расширению массива, например "${existing_args[@]}".
  • existing_args определяется как массив - список строк, а не как отдельная строка. Это важно, поскольку имена файлов сами по себе являются строками, и попытка выполнить итерацию по строке, как если бы это был список, обычно содержит ошибки (опять-таки это влияет на файлы с пробелами, буквенными символами новой строки, символами глобуса и т. Д. В их именах).
  • Использование find -print0 гарантирует, что мы используем NUL-разделители наших имен файлов. Это важно, потому что имена файлов в UNIX передаются как строки, разделенные NUL; Таким образом, NUL является единственным символом, который гарантированно не присутствует в пути. IFS= read -r -d '' var читает одну запись из такой строки, разделенной NUL.
  • Использование < <(...) гарантирует, что мы перенаправляем из вывода ... в цикл, который является предметом этого перенаправления, при этом помещая find - а не цикл - в подоболочку. Пример того, почему это важно, см. BashFAQ # 24 .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...