Bash для цикла с подстановочными знаками и скрытыми файлами

Просто с простым скриптом оболочки и немного запутанным:

Вот мой сценарий:

% for f in $FILES; do echo "Processing $f file.."; done

Команда:

ls -la | grep bash 

производит:

% ls -a | grep bash
.bash_from_cshrc
.bash_history
.bash_profile
.bashrc

Когда

FILES=".bash*"

Я получаю те же результаты (другое форматирование), что и ls -a. Однако когда

FILES="*bash*"

Я получаю этот вывод:

Processing *bash* file..

Это не ожидаемый результат и не то, что я ожидаю. Можно ли использовать подстановочный знак в начале имени файла? Это . в начале имени файла "особое" как-то?

Параметр

FILES="bash*"

Тоже не работает.


person sixtyfootersdude    schedule 25.01.2010    source источник
comment
Как сказал Nos ниже, вы, вероятно, захотите использовать флаг bash для изменения поведения. (магазин -s dotglob)   -  person Chris Quenelle    schedule 26.01.2010
comment
Этот вопрос чаще всего встречается, когда я ищу скрытые файлы с подстановочными знаками bash. Я предлагаю изменить принятие на ответ с наибольшим количеством голосов, который является общим решением, которое люди должны использовать при борьбе с этой проблемой.   -  person Andras Deak    schedule 02.05.2020


Ответы (5)


FILES=".bash*" работает, потому что имена скрытых файлов начинаются с .

FILES="bash*" не работает, потому что имена скрытых файлов начинаются с ., а не с b

FILES="*bash*" не работает, потому что подстановочный знак * в начале строки пропускает скрытые файлы.

person gregseth    schedule 25.01.2010
comment
Итак, если я хочу это сделать, я должен сделать FILES=.*bash*? Но что, если мне нужны скрытые И не скрытые файлы? - person sixtyfootersdude; 26.01.2010

Подстановка по умолчанию в bash не включает имена файлов, начинающиеся с . (так называемые скрытые файлы).

Вы можете изменить это с помощью

shopt -s многоточие

$ ls -a
.  ..  .a  .b  .c  d  e  f
$ ls *
d  e  f
$ shopt -s dotglob
$ ls *
.a  .b  .c  d  e  f
$ 

Чтобы отключить его снова, запустите shopt -u dotglob.

person nos    schedule 25.01.2010

Если вы хотите скрыть и не скрыть, установите dotglob (bash)

#!/bin/bash
shopt -s dotglob
for file in *
do
 echo "$file"
done
person ghostdog74    schedule 26.01.2010

Да, . в начале является особенным и обычно не будет соответствовать подстановочному знаку *, как описано на справочной странице bash (и является общим для большинства оболочек Unix):

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

person alanc    schedule 25.01.2010

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

for f in .[!.]* *; do
    echo "Processing $f file.."
done

Подстановочный знак .* расширится на все точечные файлы, но включает родительский каталог, который вы обычно хотели бы исключить; поэтому .[!.]* соответствует всем файлам, у которых первый символ — точка, а второй — нет.

Если у вас есть другие файлы с двумя начальными точками, вам нужно указать третий подстановочный знак, чтобы покрыть их, но исключить родительский каталог! Попробуйте ..?*, для которого требуется, чтобы после второй точки был хотя бы один символ.

person tripleee    schedule 20.05.2021