Результат ls *, ls ** и ls ***


86

Я знаю, что с помощью команды lsбудут перечислены все каталоги. Но что делает ls *команда? Я использовал это, и это просто перечисляет каталоги. Звезда перед значком lsозначает, насколько глубоко она может перечислить каталоги?

Ответы:


155

lsперечисляет файлы и содержимое каталогов, которые передаются в качестве аргументов, и если аргумент не задан, в нем отображается текущий каталог. Также может быть передан ряд опций, которые влияют на его поведение (подробнее см. man ls).

Если lsпередается вызываемый аргумент *, он будет искать файл или каталог, вызываемый *в текущем каталоге, и перечислять его, как и любой другой. lsне относится к *персонажу каким-либо иным способом, кроме как к другому.

Однако , если ls *это оболочка командной строки, то оболочка будет расширяться , что в *соответствии с соответствующей оболочечному подстановка (также упоминается как Filename Generation или Filename Expansion ) правил.

В то время как разные оболочки поддерживают разные операторы глобализации, большинство из них соглашаются на самый простой *. *под шаблоном подразумевается любое количество символов, поэтому *a globрасширится до списка файлов в текущих каталогах, которые соответствуют этому шаблону. Однако есть исключение, что начальный .символ точки ( ) в имени файла должен явно совпадать, поэтому *фактически расширяется до списка файлов и каталогов, не начиная с .(в лексикографическом порядке).

Например, если текущий каталог содержит файлы , называемые ., .., .foo, -lи foo bar, *будет расширен за счет оболочки двух аргументов для передачи ls: -lи foo bar, таким образом , это будет , как если бы вы ввели:

ls -l "foo bar"

или же

'ls' "-l" foo\ bar

Какие три способа выполнить одну и ту же команду? Во всех трех случаях lsкоманде (которая, вероятно, будет выполнена из /bin/lsпоиска в каталогах, упомянутых в $PATH), будут переданы эти 3 аргумента: «ls», «-l» и «foo bar».

Кстати, в этом случае lsпервый (строго говоря, второй ) будет рассматриваться как вариант.

Теперь, как я уже сказал, у разных оболочек разные операторы сглаживания. Несколько десятилетий назад был zshвведен **/оператор¹, который означает соответствие любому уровню подкаталогов, сокращенному (*/)#и ***/который одинаков, за исключением того, что он следует по символическим ссылкам при спуске каталогов.

Несколько лет назад (июль 2003 г. ksh93o+) ksh93решили скопировать это поведение, но решили сделать его необязательным и рассмотрели только **случай (не ***). Кроме того, хотя **один не был особенным в zsh(просто означал то же самое, что *и в других традиционных оболочках, поскольку **означает любое количество символов, за которым следует любое количество символов), в ksh93 **означал то же самое, что **/*(поэтому любой файл или каталог ниже текущего (исключая скрытые файлы).

bashскопировал ksh93несколько лет спустя (февраль 2009 г., bash 4.0), с тем же синтаксисом, но прискорбным отличием: bash **был похож zshна s ***, то есть он следовал по символическим ссылкам при повторном обращении в подкаталоги, что обычно не то, что вы хотите, и может иметь неприятные побочные эффекты. Это было частично исправлено в bash-4.3, так как символические ссылки все еще использовались, но рекурсия на этом остановилась. Это было полностью исправлено в 5.0.

yashдобавлен **в версии 2.0 в 2008 году, включен с extended-globопцией. Его реализация ближе к тому zsh, что **только в этом нет ничего особенного. В версии 2.15 (2009), добавил он , ***как в zshи два собственных расширений: .**и .***включить скрытые каталоги при рекурсии (в zsh, то D Глоб классификатор (как **/*(D)) будет рассматривать скрытые файлы и папки, но если вы хотите , чтобы пройти скрытый dirs но не раскрывайте скрытые файлы, вам нужно ((*|.*)/)#*или **/[^.]*(D)).

Ракообразные также поддерживает **. Как и в предыдущей версии bash, он следует по символическим ссылкам при спуске по дереву каталогов. В этой оболочке, однако **/*, не то же самое, что **. **это расширение, *которое может охватывать несколько каталогов. В fish, **/*.cбудет соответствовать , a/b/c.cно не a.c, в то время как a**.cбудет соответствовать a.cи ab/c/d.cи zsh«s **/.*, например , должно быть написано .* **/.*. Там ***понимается как **следует *так же, как и **.

tcshтакже добавлена globstarопция в V6.17.01 (май 2010 г.) и поддерживается как **и ***а-ля zsh.

Так tcsh, bashи ksh93(если соответствующая опция ( globstar)) или fish, **разворачивает все файлы и каталоги ниже текущего, и ***такая же , как **для fish, символьной ссылки , пересекающей **для tcshс globstar, и так же , как *в bashи ksh93(хотя это не исключено, что будущие версии этих оболочек будут также проходить по символическим ссылкам).

Выше вы заметили необходимость убедиться, что ни одно из расширений не интерпретируется как опция. Для этого вы должны сделать:

ls -- *

Или же:

ls ./*

Есть некоторые команды (это не имеет значения ls), где вторая предпочтительнее, поскольку даже с --некоторыми именами файлов могут быть обработаны специально. Это дело -для большинства текстовых утилит, cdа pushdи имена файлов , которые содержат =символ для awk, например. Приставка ./ко всем аргументам убирает их особое значение (по крайней мере, для случаев, упомянутых выше).

Следует также отметить, что большинство оболочек имеют ряд опций, которые влияют на поведение сглаживания (например, игнорируются ли точечные файлы, порядок сортировки, что делать, если нет совпадений ...), см. Также $FIGNOREпараметр вksh

Кроме того , в любой оболочке , но csh, tcsh, fishи zsh, если подстановка шаблон не соответствует любому файлу, шаблон передается в качестве аргумента нераскрытого , что вызывает путаницу и , возможно , ошибку. Например, если в текущем каталоге нет скрытого файла

ls *

На самом деле позвонит lsс двумя аргументами lsи *. И так как файла нет вообще, поэтому ни один из них не вызван *, вы увидите сообщение об ошибке от ls (не от оболочки) вроде:, ls: cannot access *: No such file or directoryкоторый, как известно, заставляет людей думать, что это lsдействительно расширяет глобусы.

Проблема еще хуже в таких случаях, как:

rm -- *.[ab]

Если нет никакого , *.aни *.bфайл в текущем каталоге, то вы можете в конечном итоге удалить файл с именем *.[ab]по ошибке ( csh, tcshи zshбудет сообщать не ровня ошибку и не назвал бы rmfishне поддерживает [...]подстановочные знаки)).

Если вы хотите передать литерал *в ls, вы должны указать этот *символ каким-либо образом, например, в ls \*или ls '*'или ls "*". В POSIX-подобных оболочках глобализация может быть полностью отключена с помощью set -o noglobили set -f(последняя не работает, zshесли в sh/ kshэмуляции).


¹ Хотя (*/)#это всегда поддерживалось, сначала оно было коротким, как ..../в zsh-2.0 (и, возможно, раньше), затем ****/в 2.1, прежде чем получить окончательную форму **/в 2.2 (начало 1992 года).


22
Действительно отличный ответ!
Андреа Корбеллини

7
Еще один хороший пример find -name *. Особенно с более сложными шаблонами, если в текущем каталоге есть только одно совпадение, люди часто не поймут, что не передают звездочку find.
njsg

Я продолжаю давать +1, я действительно рад видеть Стефана Чазела активным здесь на unix.stackexchange.com ! Большой вклад, Стефан, как всегда!
Дмитрий Радулов

1
В рыбе *.[ab]попытался бы удалить все, заканчивающиеся на .[ab]. [не особенный в рыбе.
Конрад Боровски

35

Команда по lsумолчанию ls .: Список всех записей в текущем каталоге .

Команда ls *означает «запустить ls при расширении *шаблона оболочки»

*Шаблон обрабатывается оболочкой, и расширяется до всех записей в текущем каталоге, за исключением тех , которые начинаются с .. Это пойдет на один уровень глубже.

Интерпретация двойных или тройных *паттернов зависит от фактической используемой оболочки.

*подстановочный знак, который соответствует 0 или более символов. Некоторые современные оболочки будут видны в подкаталогах при просмотре **шаблона.


17
За исключением того, что дополнительные * действительно добавить что-то, см. Другой ответ, объясняющий Globstar. Следует также прояснить, что ls не имеет ничего общего со звездочками, он никогда не пропускает ни одну из этих звездочек. Запустите, echo ls *чтобы увидеть, что будет выполнено, когда вы напишите ls *.
njsg

12

Вы можете демистифицировать весь процесс, набрав echoвместо lsпервого, чтобы увидеть, к чему относится команда:

$ echo *
Applications Downloads Documents tmp.html

Так что в этом случае ls *расширяется доls Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

Так что без изменений. Это предполагает, что вы используете в bashкачестве оболочки - большинство людей, и разные оболочки имеют разное поведение. Если вы используете ashили cshили kshили zsh, вы можете ожидать, что все будет работать по-другому. Вот в чем смысл наличия разных оболочек.

Итак, давайте попробуем что-то другое (все еще с bash), чтобы мы могли понять, что *оператор globbing ( ) может сделать для нас. Например, мы можем фильтровать по части имени:

$ echo D*
Downloads Documents

И что интересно, завершающий слеш неявно является частью любого имени каталога. Таким образом, */будут выдаваться только каталоги (и символические ссылки на каталоги):

$ echo */
Applications/ Downloads/ Documents/

И мы можем сделать некоторую фильтрацию на нескольких уровнях, поместив косую черту в середине:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

Поскольку Downloadsкаталог не содержит никаких подкаталогов, он не попадает в вывод. Это очень полезно только для изучения файлов, которые вы хотите. Я все время использую такие команды:

$ ls -l /home/*/public_html/wp-config.php

В этом списке перечислены все wp-config.phpфайлы, которые существуют на базовом уровне в public_htmlкаталоге любого пользователя . Или, возможно, чтобы быть более полным:

$ find /home/*/public_html/ -name wp-config.php

Это позволит найти любые wp-config.phpфайлы в любого пользователя public_htmlкаталогов или любой из их подкаталогов, но он будет работать более эффективно , чем просто find /home/ -name wp-config.phpпотому , что он не будет ничего исследовать , но в public_htmlкаталогах для каждого из пользователей.


1
«Предполагается, что вы используете в bashкачестве оболочки» ← и что globstar не включен. shopt -s globstarи попробуйте снова ...
njsg

Другой способ демистификации состоит в set -xтом, чтобы начать печатать «фактическую» команду, выполняемую каждый раз (выключить с помощью set +x).
ShreevatsaR

10

В некоторых оболочках, включая bash 4.x с globstarвключенной опцией, **будет выполняться рекурсивный глобус, нисходящий совпадающий каталог. Дополнительные звездочки больше не изменяют эту операцию.


1
Однако, как я уже сказал в своем ответе, остерегайтесь того, что, вопреки ksh93и zsh, bashпересекает символические ссылки в рекурсии, которая обычно нежелательна.
Стефан Шазелас

Это было исправлено в bash 4.3
Стефан Шазелас

1

Если вы хотите "погрузиться глубже", используйте опцию ls -R (recursive) или используйте find, например так:

find . -ls

«find» опустится до нижней части дерева каталогов (как и «ls -R») и имеет много других опций, таких как перечисление каталогов (-type d), только файлов (-type f) или показ файлов, имеющих другие характеристики (нет пользователя в / etc / passwd, особые права и многое другое). «find» также несколько безопаснее в сценариях (из-за непоследовательных правил подстановки между оболочками, а также из-за специальных экранирований для файлов с тире и т. д.).

Подстановочные символы оболочки не будут работать с звездочкой '*' в точечных файлах. Чтобы перечислить только точечные файлы, используйте:

ls .??*


-1

Extra * не добавляет уровень глубины. Но если вы попробуете

 ls */*/*

- вы получите список подпапок подпапок в папках в текущей папке ...


Неправильно. В зависимости от оболочки дополнительные *s добавят уровень глубины.
njsg

так какая оболочка добавит уровень глубины на дополнительные звезды?
VB9-UANIC

Несколько. Включая GNU bashс опцией globstar, оболочку korn и zsh. И, возможно, другие, я думаю. unix.stackexchange.com/a/62665/14831
njsg

-1

Мое основное преимущество заключается в том, что echo ** / *. Ext обычно ...

Может или не может: перечислить файл .ext в текущем каталоге

Может или не может: включить. *. Ext файлы

Как правило, я бы предпочел, чтобы выражение glob было '** /' и могло привести к пустой строке (без подкаталога). Вот как я конвертирую выражения glob в программный ввод. Конечно, я уверен, что есть комментарии, объясняющие это в примерах использования.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.