Чому nullglob не використовується за замовчуванням?


61

У більшості оболонок nullglobза замовчуванням не є. Це означає, наприклад, якщо ви запускаєте цю команду

ls *

у порожньому каталозі він розширить *глобус на буквальний *, а не на порожній список аргументів. Існують способи змінити таку поведінку, щоб *у порожній каталог повернувся порожній список аргументів, який здавався б більш інтуїтивним.

Отже, чи є причина, чому nullglobвимкнено за умовчанням? Якщо так, то яка причина?


13
Хтось колись зробив поганий вибір, який перетворився на "ми завжди робили це так". Дуже повсюдне явище (не тільки) у світі програмного забезпечення.
PSkocik

4
Початкова причина полягає в тому, що опція nullglob тоді ще не існувала. Щоб зберегти зворотну сумісність, її потрібно відключити за замовчуванням.
PM 2Ring

3
Хоча в ньому конкретно не згадується нульовий глобул, деяку історію глобалізації надає ця відповідь: unix.stackexchange.com/a/136409/22724
StrongBad

4
У мене складається враження, що деякі вважають, що має бути очевидним, що nullglob повинен бути включений за замовчуванням. Я не думаю, що це очевидно. Те, що розширення трапляються в оболонці перед викликом команди, означає, що розширення ні до чого не є менш інтуїтивним поведінкою, ніж глобус, який залишається незмінним.
Кідро

2
@kojiro Менш інтуїтивно зрозумілий? Кожен, хто має ознайомлення з оболонками * NIX, знає, що *це глобус, і розширюється на всі існуючі файли; наскільки "інтуїтивно зрозумілим" є спеціальний випадок, коли порожні глобуси каталогів "розширені" до буквального *?
Кайл Странд

Відповіді:


78

nullglobВаріант (який до речі є zshвинаходом, тільки додав роки по тому bash( 2.0)) , не було б ідеальними в ряді випадків. І lsце хороший приклад:

ls *.txt

Або його більш правильний еквівалент:

ls -- *.txt

З nullglobon запускається lsбез аргументу, який трактується як ls -- .(перерахуйте поточну директорію), якщо жоден файл не збігається, що, ймовірно, гірше, ніж виклик lsз літералом *.txtяк аргумент.

У вас є подібні проблеми з більшості текстових утиліт:

grep foo *.txt

Буде шукати fooна stdin, якщо немає txtфайлу.

Більш розумний за замовчуванням, і той, що відповідає csh, tcsh, zsh або fish 2.3+ (і ранніх оболонок Unix), це взагалі скасувати команду, якщо глобус не відповідає.

bash(оскільки у версії 3) є failglobваріант для цього (цікаво для цієї дискусії, оскільки всупереч ashAT&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/globhelper, і цей помічник поводився так csh: він би провалив команду, якщо жоден з глобусів не відповідав жодному файлу і не видалить глобус, не інакше.

Тож ситуація, в якій ми сьогодні, пояснюється поганим рішенням, прийнятим в оболонці Борна.

Зауважте, що оболонка Bourne (і оболонка C) оснащена ще однією новою функцією Unix: довкілля. Це означало змінне розширення (у попередника були лише $1, $2... позиційні параметри). Оболонка Bourne також ввела підстановку команд.

Ще одним поганим дизайнерським рішенням оболонки Борна було проведення глобалізації (і розщеплення) після розширення змінних та підстановки команд (можливо, для зворотної сумісності з оболонкою Томпсона, де echo $1все-таки можна було б викликати, /etc/globякщо $1містилися бідні символи (це було більше схоже на розширення макросу попереднього процесора) там, як у розгорнутому значенні, знову розбирався як код оболонки)).

Невдалі глобуси, які не відповідають, означають, наприклад, що:

pattern='a.*b'
grep $pattern file

не вдасться виконати команду (якщо a.whateverbв поточному каталозі немає деяких файлів). csh(який також виконує глобалізацію при змінному розширенні) не спрацьовує команда в цьому випадку (і я можу стверджувати, що це краще, ніж залишати спокійну помилку там, навіть якщо це не так добре, як не робити глобалізацію взагалі, як у zsh).


Існує ще одна проблема юзабіліті: nullglobз'являється помилка завершення вкладки (натискання клавіші вкладки нічого не робить, коли вона включена).
Кайл Странд

1
Можливо використовувати nullglob на основі glob за допомогою bash - хоча синтаксис не такий елегантний, як zshfiles=$(shopt -s nullglob;echo *.txt)
Jon Nalley

2
@JonNalley, який зберігає конкатенацію (з пробілом) імен файлів (з можливим перетворенням xpg_echo) у скалярні змінні. Ви повинні були б що - щось подібне readarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)з bash4.4 або вище , або (shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmdз GNU xargsдля того , щоб можна було використовувати на всі з довільними іменами файлів. Або, все-таки з bash4.4, використовуйте помічну функцію, яка використовує local -(скопійовано з золи 25 років пізніше) для локальної області для опцій.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.