Шаблон имени файла Shell, который расширяется для отмечания точкой файлов, но не к '..'?

Согласно Rajesh, добавляя опцию к серверу казался лучшим способом пойти.
Посмотрите этот вопрос для полных деталей

13
02.01.2014, 04:03
2 ответа

Bash, ksh и zsh имеют лучшие решения, но в этом ответе я принимаю оболочку POSIX.

Шаблон .[!.]* соответствия все файлы, которые начинаются с точки, сопровождаемой неточечным символом. (Отметьте это [^.] поддерживается некоторыми оболочками, но не всеми, портативный синтаксис для дополнения набора символов в подстановочных шаблонах [!.].) Это поэтому исключает . и .., но также и файлы, которые начинаются с двух точек. Шаблон ..?* файлы дескрипторов, которые начинаются с двух точек и не являются просто ...

chown -R root .[!.]* ..?*

Это - классический набор шаблона для соответствия всем файлам:

* .[!.]* ..?*

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

  • Использовать * .* перечислить все записи и исключить . и .. в цикле. Один или оба из шаблонов ничему не может соответствовать, таким образом, цикл должен проверить на существование каждого файла. У Вас есть возможность отфильтровать на других критериях; например, удалите -h протестируйте, если Вы хотите пропустить повисшие символьные ссылки.

    for x in * .*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
    
  • Более сложный вариант, куда команда выполняется только однажды. Обратите внимание, что позиционные параметры ударены (оболочки POSIX не имеют массивов); поместите это в отдельную функцию, если это - проблема.

    set --
    for x in * .[!.]* ..?*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      set -- "$@" "$x"
    done
    somecommand "$@"
    
  • Используйте * .[!.]* ..?* триптих. Снова, один или несколько шаблонов ничему не может соответствовать, таким образом, мы должны проверить на существующие файлы (включая свисание символьных ссылок).

    for x in * .[!.]* ..?*; do
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
    
  • Используйте * .[!.]* ..?* tryptich, и выполненный команда однажды на шаблон, но только если это соответствовало чему-то. Это выполняет команду только однажды. Обратите внимание, что позиционные параметры ударены (оболочки POSIX не имеют массивов), поместите это в отдельную функцию, если это - проблема.

    set -- *
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- .[!.]* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- ..?* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    somecommand "$@"
    
  • Использовать find. С GNU или BSD находят, избегая, чтобы рекурсия была легка с опциями -mindepth и -maxdepth. С POSIX находят, это немного более хитро, но может быть сделано. Эта форма имеет преимущество легкого разрешения выполнить команду единственное время вместо однажды на файл (но это не гарантируется: если получающаяся команда будет слишком длинной, то команда будет выполнена в нескольких пакетах).

    find . -name . -o -exec somecommand {} + -o -type d -prune
    
20
27.01.2020, 19:52

Это работает, если все имена файлов содержат по крайней мере три символа (включая точку):

chown -R root .??*

Для большего надежного решения можно использовать find:

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;
6
27.01.2020, 19:52

Теги

Похожие вопросы