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


86

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

Відповіді:


155

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

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

Однак , якщо ls *це оболонка командного рядка, то оболонка буде розширюватися , що в *відповідно до відповідної оболонкові підстановка (також згадується як Filename Generation або Filename Expansion ) правил.

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

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

ls -l "foo bar"

або

'ls' "-l" foo\ bar

Які три способи запустити абсолютно одну команду. У всіх 3 випадках lsкоманда (яка, ймовірно, буде виконана з /bin/lsпошуку каталогів, згаданих у $PATH), передасть ці 3 аргументи: "ls", "-l" та "foo bar".

Між іншим, в цьому випадку lsбуде розглядатись перший (строго кажучи другий ) варіант.

Зараз, як я вже сказав, різні оболонки мають різних операторів, що займаються глобалізацією. Кілька десятиліть тому, zshпредставив **/operator¹ , що означає , щоб відповідати будь-якого рівня підкаталогів, скорочення (*/)#і ***/що те ж саме , за винятком того , що слід симлінк при спуску каталогів.

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

bashскопійовано ksh93через кілька років (лютий 2009 р., bash 4.0) з тим самим синтаксисом, але прикрою різницею: bash's **було схоже на 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чи проходить символічна посилання в рекурсії, яка взагалі небажана.
Стефан Шазелас

Це тепер було зафіксовано в
басі

1

Якщо ви хочете "зануритися вглиб", скористайтеся параметром ls -R (рекурсивний) або використовуйте "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

Моя головна хватка полягає в тому, що відлуння ** / *. Ext, як правило, ...

Травень чи травень: список файлу .ext у поточному каталозі

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

Як правило, я вважаю за краще вираз глобуса "** /", який може призвести до нульового рядка (немає підкаталогу). Ось так я перетворюю глобальні вирази у вхід програми. Звичайно, я страхую, що є коментарі, що пояснюють це на прикладах використання.

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