Я хотів би запитати:
Чому echo {1,2,3}
розширено до 1 2 3, що є очікуваною поведінкою, а echo [[:digit:]]
повертається, [[:digit:]]
коли я очікував, що він надрукує всі цифри від 0
до 9
?
Я хотів би запитати:
Чому echo {1,2,3}
розширено до 1 2 3, що є очікуваною поведінкою, а echo [[:digit:]]
повертається, [[:digit:]]
коли я очікував, що він надрукує всі цифри від 0
до 9
?
Відповіді:
Бо це дві різні речі. Це {1,2,3}
приклад розширення дужок . {1,2,3}
Конструкція розширюється оболонкою , до того echo
навіть НЕ бачить. Ви можете бачити, що станеться, якщо ви використовуєте set -x
:
$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3
Як бачимо, команда echo {1,2,3}
розширюється на:
echo 1 2 3
Однак [[:digit:]]
це клас символів POSIX . Коли ви віддаєте його echo
, оболонка також спочатку обробляє його, але цього разу обробляється як глобус оболонки . він працює так само, як і при запуску, echo *
який буде друкувати всі файли в поточному каталозі. Але [[:digit:]]
це глобус оболонки, який відповідатиме будь-якій цифрі. Тепер у bash, якщо глобул оболонки нічого не відповідає, він буде розширений до себе:
$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files
Якщо глобус щось відповідає, це буде надруковано:
$ echo /e*c
+ echo /etc
/etc
В обох випадках echo
просто друкується все те, що оболонка підказує для друку, але у другому випадку, оскільки глобус щось відповідає ( /etc
), йому потрібно сказати, що щось роздрукувати.
Отже, оскільки у вас немає файлів чи каталогів, ім'я яких складається саме з однієї цифри (що [[:digit:]]
відповідатиме), глобус розширюється до себе, і ви отримуєте:
$ echo [[:digit:]]
[[:digit:]]
Тепер спробуйте створити файл з назвою 5
та виконувати ту ж команду:
$ echo [[:digit:]]
5
І якщо є декілька відповідних файлів:
$ touch 1 5
$ echo [[:digit:]]
1 5
Це (подібне) задокументоване в man bash
поясненні nullglob
варіантів, які вимикають таку поведінку:
nullglob
If set, bash allows patterns which match no files (see
Pathname Expansion above) to expand to a null string,
rather than themselves.
Якщо встановити цей параметр:
$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]] ## prints nothing
$
shopt -s failglob
щоб отримати більш корисну поведінку, подібну до поведінки сучасних снарядів типу zsh
або fish
.
failglob
. nullglob
може спричинити несподівані проблеми, наприклад, при вставці URL-адреси, у якої, можливо, є ?
.
nullglob
щоб продемонструвати, що модель оболонки інтерпретується як глобус.
{1,2,3}
є дуговим розширенням , воно розширюється на слова, перелічені без огляду на їх значення.
[...]
- це символьна група, яка використовується в розширенні імені файлів (або підстановці, або в глобусі) аналогічно зірочці *
та знаку запитання ?
. Він відповідає будь-якому одному символу, переліченому всередині, або символам, які є членами названих груп, наприклад, [:digit:]
якщо такі перераховані. Поведінка більшості оболонок за замовчуванням полягає в тому, щоб залишити підстановку такою, що є, якщо немає файлів, які відповідають їй.
(Зауважте, що ви не можете реально перетворити підстановку / візерунок у набір рядків, яким він би відповідав. Зірочка може відповідати будь-якій рядку будь-якої довжини, тому розширення будь-якого шаблону, що містить її, створить нескінченний список рядків.)
Тому:
$ bash -c 'echo [[:digit:]]' # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]' # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]' # now there are two matches
1 3 # note that d, i, g and t do NOT match
Але все ж:
$ bash -c 'echo {1,2,3}'
1 2 3
Обидва розширені оболонкою , не має значення, чи є команда, яку ви виконуєте ls
, echo
або rm
. Також зауважте, що якщо цитується будь-яке з них, вони не будуть розширені:
$ bash -c 'echo "[[:digit:]]"' # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}
[[:digit:]]
перед тим, як передати її echo
, тому echo
ніколи не бачить [[:digit:]]
, вона бачить тільки 1 3
. Ви можете побачити це в дії, запустивши, set -x
який буде надрукувати фактичні команди, які виконуються (запустіть, set +x
щоб вимкнути його знову).
echo
не шукає файли, оболонка , перед тим, як запустити echo
.
{1,2,3}
(наприклад {1..3}
, розширення дужок . Вони інтерпретуються оболонкою перед виконанням команди.
[[:digit:]]
- це маркер відповідності шаблону , але ви не використовуєте його в розташуванні з файлами, які відповідають цьому шаблону. Якщо ви використовуєте відповідність шаблону, яка не відповідає, вона розширюється до себе:
$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3