nullglob
Варіант (який до речі є zsh
винаходом, тільки додав роки по тому bash
( 2.0
)) , не було б ідеальними в ряді випадків. І ls
це хороший приклад:
ls *.txt
Або його більш правильний еквівалент:
ls -- *.txt
З nullglob
on запускається ls
без аргументу, який трактується як ls -- .
(перерахуйте поточну директорію), якщо жоден файл не збігається, що, ймовірно, гірше, ніж виклик ls
з літералом *.txt
як аргумент.
У вас є подібні проблеми з більшості текстових утиліт:
grep foo *.txt
Буде шукати foo
на stdin, якщо немає txt
файлу.
Більш розумний за замовчуванням, і той, що відповідає csh, tcsh, zsh або fish 2.3+ (і ранніх оболонок Unix), це взагалі скасувати команду, якщо глобус не відповідає.
bash
(оскільки у версії 3) є failglob
варіант для цього (цікаво для цієї дискусії, оскільки всупереч ash
AT&T ksh
або zsh
, bash
не підтримує локальні області застосування опцій (хоча це має змінитись у 4.4), цей варіант, коли включений у всьому світі, порушує декілька речей як функція доповнення bash).
Зверніть увагу , що CSH і Tcsh трохи відрізняється від zsh
, fish
або bash -O failglob
в таких випадках , як:
ls -- *.txt *.html
Там, де вам потрібно, щоб усі глобуси не відповідали команді, яку потрібно скасувати. Наприклад, якщо є один txt-файл і немає html-файлу, це стає:
ls -- file.txt
Ви можете отримати таку поведінку за zsh
допомогою, setopt cshnullglob
хоча більш розумним способом зробити це zsh
було б використовувати глобус на зразок:
ls -- *.(txt|html)
В zsh
і ksh93
ви також можете застосувати nullglob на основі глобусу, що є набагато безпечнішим підходом, ніж зміна глобальної настройки:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
створив би порожній масив, якщо немає txt
файлу замість помилки команди з помилкою (або зробити її масивом з одним *.txt
буквальним аргументом з іншими оболонками).
Версії fish
до 2.3 працювали б як, bash -O nullglob
але попереджають, коли інтерактивні, коли глобус не відповідає. Починаючи з 2.3, він працює як zsh
крім глобусів, які використовуються в for
, set
або count
.
Тепер, на замітці історії, поведінку насправді порушила оболонка Борна. У попередніх версіях Unix глобалізація здійснювалася через /etc/glob
helper, і цей помічник поводився так csh
: він би провалив команду, якщо жоден з глобусів не відповідав жодному файлу і не видалить глобус, не інакше.
Тож ситуація, в якій ми сьогодні, пояснюється поганим рішенням, прийнятим в оболонці Борна.
Зауважте, що оболонка Bourne (і оболонка C) оснащена ще однією новою функцією Unix: довкілля. Це означало змінне розширення (у попередника були лише $1
, $2
... позиційні параметри). Оболонка Bourne також ввела підстановку команд.
Ще одним поганим дизайнерським рішенням оболонки Борна було проведення глобалізації (і розщеплення) після розширення змінних та підстановки команд (можливо, для зворотної сумісності з оболонкою Томпсона, де echo $1
все-таки можна було б викликати, /etc/glob
якщо $1
містилися бідні символи (це було більше схоже на розширення макросу попереднього процесора) там, як у розгорнутому значенні, знову розбирався як код оболонки)).
Невдалі глобуси, які не відповідають, означають, наприклад, що:
pattern='a.*b'
grep $pattern file
не вдасться виконати команду (якщо a.whateverb
в поточному каталозі немає деяких файлів). csh
(який також виконує глобалізацію при змінному розширенні) не спрацьовує команда в цьому випадку (і я можу стверджувати, що це краще, ніж залишати спокійну помилку там, навіть якщо це не так добре, як не робити глобалізацію взагалі, як у zsh
).