Я играл с расширением, и я заметил своеобразное поведение. Я пытался сделать:
echo ./*.txt
И у меня не было никакого файла .txt в моем текущем каталоге. Вывод, который я получил, был:
./*.txt
Мне просто любопытно: почему я это получил? Я ожидал не получить никакого вывода.
PS: когда у меня был .txt
файл, расширение было правильно истолковано. Другими словами, скажем, у меня был файл, smthn.txt
эхо фактически повторилось current_directory/smthn.txt
.
источник
shopt -s nullglob
выдаст пустые строки для несопоставленных шаблонов иshopt -u nullglob
(стандартная настройка) выдаст сам шаблон.Если бы
nullglob
они использовались по умолчанию, многие команды вели бы себя совершенно неожиданно, потому что, как правило (к сожалению), команды обрабатывают случай нулевых аргументов имени файла качественно иным образом, чем один или несколько аргументов имени файла.Предположим, что вы включили
nullglob
(shopt -s nullglob
), и вы находитесь в каталоге, где не найдено ни одного файла*.txt
. Тогда*.txt
действительно расширится до нуля - не пустое поле, а вообще никаких полей - как вы и ожидали. Но это будет иметь следующие результаты:ls *.txt
будет перечислять все файлы в текущем каталоге (кроме скрытых файлов), потому что это то, чтоls
происходит, когда вы не передаете ему аргументы имени файла.cat *.txt
будет читать со стандартного ввода , потому что, когдаcat
нет аргументов имени файла, это как если бы вы работалиcat -
. Если он работает в интерактивном режиме, он сидит в ожидании ввода. Многие команды ведут себя таким образом.cp *.txt dest/
потерпит неудачу с ошибкойcp: missing destination file operand after 'dest/'
. Это не катастрофа, но это сбивает с толку и весьма отличается от молчаливого успеха, который, вероятно, желателен.file *.txt
и различные другие программы, не имеющие специального поведения для случая нулевых аргументов имени файла, все равно будут с ошибкой или сообщением об использовании, если ни одна из них не будет передана.printf 'Got file: "%s"\n' *.txt
будет печататьGot file: ""
вместо ничего.*
,?
и[
что не предполагается расширить оболочку бы чаще производить очевидно неправильные результаты, но таким образом , что может быть трудно понять. Например, если имена файлов в текущем каталоге не начинаютсяgedit
, тоapt list gedit*
(где этоapt list 'gedit*'
было задумано) станет простоapt list
и перечислит все доступные пакеты.Так что хорошо, что вы не получаете такое поведение, не запрашивая его. Вероятно, наиболее распространенной практической ситуацией, которая на самом деле упрощается,
nullglob
являетсяfor f in *.txt
. Смотрите также этот вопрос (с которым связался ответ Сергея Колодяжного ).Сложнее ответить на вопрос, почему
failglob
- если ошибка расширения, связанная с тем, что глобус не соответствует ни одному файлу, - не используется по умолчанию в bash. Я считаю, что ответ Сергея Колодяжного фиксирует причину этого, даже не обращаясь к нему напрямую. Сохранение нерасширяющихся глобусов без возникновения ошибки расширения является (возможно, к сожалению) стандартизированным поведением, а также традиционным и, следовательно, ожидаемым поведением. Хотя bash не пытается быть полностью POSIX-совместимым, если он не вызывается с именемsh
или не передается--posix
опция, многие из его вариантов разработки, даже когда не в режиме POSIX, следуют непосредственно за POSIX. Им пришлось выбрать какое-то поведение, и есть недостатки, связанные с несоответствием ожиданиям пользователей.Я думаю, что это наименее исторически влиятельный аспект этого вопроса, поэтому я сохранил его напоследок ... но стоит упомянуть, что в
nullglob
поведении есть что-то немного странно концептуальное .nullglob
на первый взгляд кажется элегантным, поскольку синтаксически он рассматривает случай совпадения файлов с нулями ничем не иначе, как случай с одним, двумя или любым другим числом. Команды, которые мы запускаем, для которых глобусы расширяются в аргументы, не склонны рассматривать их одинаково, как подробно описано выше. Но синтаксически это, по крайней мере, кажется правильным, и я думаю, что это мотивация для вашего вопроса.И, тем не менее, есть еще одно, более тонкое несоответствие, которое
nullglob
не устраняется - оно на самом деле усиливается. Случай с нулевыми символами глобинга («подстановочные знаки») трактуется совершенно иначе, чем случай с одним, двумя или любым другим числом. Например, с помощьюshopt -s nullglob
, еслиab?d?f
файлы не совпадают, они удаляются; еслиab?d
файлы не совпадают, они удаляются; но еслиab
не совпадает ни с одним файлом (то есть, если нет файла, имя которого точноab
), он все равно не удаляется. Конечно, это будет катастрофа, если она будет удалена, потому что она может вообще не ссылаться на существующий файл в текущем каталоге; это может даже не ссылаться на файл. Но это все еще устраняет любую надежду на полную последовательность.Три поведения, которые предоставляет bash - по умолчанию обработка глобусов, которые не соответствуют ни одному из файлов, как если бы они не были глобусами, и передача их нерасширенными, поведение, которое вы ожидали от них (если вы простите этот странный поворот фразы) как означающий все нули файлов, которые соответствуют match (
nullglob
), и безопасное поведение, учитывающее их ошибки (failglob
) - все они представляют разные подходы к неоднозначности, присущей оболочке, и не могут знать, предназначено ли какое-либо конкретное слово быть имя файла. Оболочка выполняет свои расширения без знания того, как конкретные команды, которые вы вызываете с ней, будут обрабатывать свои аргументы.Это один из многих случаев разделения интересов . В системах, дизайн которых соответствует философии Unix, каждая часть предназначена для того, чтобы делать что-то одно и делать это хорошо . Оболочка обрабатывает текст в команды и аргументы и вызывает те команды, большинство из которых являются внешними по отношению к самой оболочке. Это, как правило, намного приятнее и гибче, чем системы, в которых внешние команды сами отвечают за выполнение этих преобразований (как в случае традиционных командных процессоров в DOS и Windows). Но у этого есть свои случайные недостатки.
источник
failglob
. Так что это не может быть по умолчанию, потому что это не всегда поддерживается.Основная причина в том , что это стандартное поведение определяется POSIX - стандарт , который охватывает оболочки языка команд и среди других согласующих вещей шаблон (оболочек , таких как
bash
,dash
оболочки - по умолчанию в Ubuntu/bin/sh
, иksh
следовать этому стандарту). Из раздела 2.13.3 Шаблоны, используемые для расширения имени файла :Это, конечно, имеет побочный эффект - сопоставление имени файла, которое может быть буквально
*.txt
.nullglob
Вариант вbash
иzsh
могут помочь: если этой опция включена с помощьюshopt -s nullglob
(и она не включена по умолчанию , которая относится к этому вопросу), то globstar будет расширен пустой строка , если не найдены имен файлов.ksh93
имеет собственный усовершенствованный механизм сопоставления с образцом, который достигает того же эффекта~(N)*.txt
Смотрите также Почему nullglob не используется по умолчанию?
источник