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

13

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

chown -R root .*

Естественно, .*расширилось до ..чего-то вроде катастрофы.

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

Эрнест А
источник

Ответы:

20

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 это немного сложнее, но можно сделать. Преимущество этой формы заключается в том, что она позволяет легко запускать команду один раз, а не один раз для файла (но это не гарантируется: если полученная команда слишком длинная, команда будет запущена в нескольких пакетах).

    find . -name . -o -exec somecommand {} + -o -type d -prune
Жиль "ТАК - прекрати быть злым"
источник
6

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

chown -R root .??*

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

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;

источник