Несподівана поведінка із луною [[: цифра:]]


Відповіді:


34

Бо це дві різні речі. Це {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

$ 

4
Дивіться також, shopt -s failglobщоб отримати більш корисну поведінку, подібну до поведінки сучасних снарядів типу zshабо fish.
Стефан Шазелас

Я погоджуюсь зі Стефаном, використовую failglob. nullglobможе спричинити несподівані проблеми, наприклад, при вставці URL-адреси, у якої, можливо, є ?.
Кевін

1
Звичайно, я лише згадав, nullglobщоб продемонструвати, що модель оболонки інтерпретується як глобус.
тердон

14

{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}

дякую за вашу відповідь, я новачок у Linux, тому дозвольте запитати вас, як ехо пов’язане з файлами 1 3, його функція полягає в тому, щоб надрукувати свої аргументи для stdout, не шукаючи файлів, наскільки мені відомо
AbdAllah Talaat

1
@AbdAllahTalaat це не має нічого спільного з відлунням. Оболонка (наприклад, bash) "розшириться" [[:digit:]] перед тим, як передати її echo, тому echoніколи не бачить [[:digit:]], вона бачить тільки 1 3. Ви можете побачити це в дії, запустивши, set -xякий буде надрукувати фактичні команди, які виконуються (запустіть, set +xщоб вимкнути його знову).
terdon

@AbdAllahTalaat, echoне шукає файли, оболонка , перед тим, як запустити echo.
ilkkachu

Тим більше, що я вважаю, що в DOS / Windows утиліти розширюють підстановку, а не оболонку. (Я, можливо, помиляюся)
ilkkachu

Вибачте, хлопці, я змінив правильну відповідь на відповідь Тедрона, тому що його коментар містив значення, що баш - це те, що робота не лунає ... його відповідь теж містила це значення .. всі ви мені допомогли ... Я хотів, щоб я міг поставити правильна відповідь на всі ваші відповіді та коментарі
AbdAllah Talaat

4

{1,2,3}(наприклад {1..3}, розширення дужок . Вони інтерпретуються оболонкою перед виконанням команди.

[[:digit:]]- це маркер відповідності шаблону , але ви не використовуєте його в розташуванні з файлами, які відповідають цьому шаблону. Якщо ви використовуєте відповідність шаблону, яка не відповідає, вона розширюється до себе:

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

Ні, як вірно відповідають інші відповіді, шаблон узгоджено з іменами файлів.
Toby Speight
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.