Как использовать шаблон. * В bash, но исключить родительский каталог (..)?

Часто бывает, что я хочу выполнить команду для всех файлов (включая скрытые файлы) в каталоге. Когда я пытаюсь использовать

chmod g+w * .*

он изменяет разрешения для всех файлов, которые я хочу (в каталоге), и всех файлов в родительском каталоге (который я хочу оставить в покое).

Есть ли подстановочный знак, который делает правильную вещь или мне нужно начать использовать find?

Ответ 1

Вам понадобятся два шаблона glob для покрытия всех возможных "точечных файлов": .[^.]* и ..?*.

Первое совпадение со всеми элементами каталога с двумя или более символами, где первый символ является точкой, а второй символ не является точкой. Второе записывает записи с тремя или более символами, начинающимися с .. (это исключает .., потому что оно имеет только два символа и начинается с ., но включает (маловероятные) записи, такие как ..foo).

chmod g+w .[^.]* ..?*

Это должно хорошо работать в большинстве оболочек и подходит для скриптов.


Для регулярного интерактивного использования шаблоны могут быть слишком сложными для запоминания. В этих случаях у вашей оболочки может быть более удобный способ пропустить . и ... zsh всегда исключает . и .. из таких шаблонов, как .*. С помощью bash вы должны использовать переменную оболочки GLOBIGNORE.

# bash
GLOBIGNORE=.:..
echo .*

Возможно, вы захотите установить GLOBIGNORE в одном из ваших файлов настройки bash (например, .bash_profile/.bash_login или .bashrc). Остерегайтесь, однако, привыкнуть к этой настройке, если вы часто используете другие среды. Если вы запускаете команду типа chmod g+w .* в среде, где отсутствует ваша настройка, вы неожиданно закончите, включая . и .. в своей команде.

Кроме того, вы можете настроить оболочки для включения "точечных файлов" в шаблоны, которые не начинаются с явной точки (например, *).

# zsh
setopt glob_dots

# bash
shopt -s dotglob


# show all files, even "dot files"
echo *

Ответ 2

Обычно я просто использовал бы . .[a-zA-Z0-9]*, так как мои имена файлов, как правило, следуют определенным правилам, но это не поймает все возможные случаи.

Вы можете использовать:

chmod g+w $(ls -1a | grep -v '^..$')

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

Конечно, если вы просто хотите делать файлы, вы можете использовать:

find . -maxdepth 0 -type f -exec chmod g+w {} ';'

или еще одно решение, которое должно делать все файлы и каталоги, кроме .. one:

for i in * .* ; do if [[ ${i} != ".." ]] ; then chmod g+w "$i"; fi done

но теперь вы попадаете на территорию, где могут потребоваться сценарии или псевдонимы.

Ответ 3

То, что я сделал, было

tar --directory my_directory --file my_directory.tar --create `ls -A mydirectory/`

Работает отлично, ls -A my_directory расширяется до всего в каталоге, кроме . и ... Нет wierd globs и на одной строке.

ps: Возможно, кто-то скажет мне, почему это не очень хорошая идея.: Р

Ответ 4

Как насчет:

shopt -s dotglob
chmod g+w ./* 

Ответ 5

Поскольку вы не хотите устанавливать dotglob для остальной части вашего сеанса bash, вы можете установить его для одного набора команд, выполнив в этом подпроцессе:

$ (shopt -s dotglob; chmod g+w ./*)

Ответ 6

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

chmod g+w * ...*