Чому ls -d також перераховує файли, і де це документально підтверджено?


48
  • при ls --directory a*його вказівці слід перераховувати лише каталоги, починаючи зa*
  • АЛЕ в ньому перераховані файли та каталоги, починаючи з a

Запитання :

  • де я можу знайти якусь документацію з цього приводу, окрім manі infoде я думаю, що я ретельно роздивився?
  • це працює тільки в БАШ?


5
echo a*також перерахує вам файли, починаючи з a(якщо такі є). Тільки для того, щоб було зрозуміліше, що це lsробить не це, а баш.
ash108

Відповіді:


89

a*І *a*синтаксис реалізується командним, а не по lsкоманді.

Коли ви вводите текст

ls a*

у запиті оболонки оболонка розширюється a*до списку існуючих усіх файлів у поточному каталозі, імена яких починаються з a. Наприклад, він може розширюватися a*до послідовності a1 a2 a3та передавати їх як аргументи ls. Сама lsкоманда ніколи не бачить *персонажа; він бачить тільки три аргументи a1, a2і a3.

В цілях розширення підстановки «файли» посилаються на всі об'єкти в поточному каталозі. Наприклад, це a1може бути звичайний файл, a2може бути каталог і a3може бути посилання. Усі вони мають записи каталогів, і розширення підстановки символів оболонки не має значення, до якого типу цих елементів вони відносяться.

Практично у всіх оболонках, які ви, швидше за все, натрапите на (bash, sh, ksh, zsh, csh, tcsh, ...), використовуйте символи. Деталі можуть відрізнятися, але основний синтаксис *відповідності нулю або більше символів та ?відповідності будь-якому одному символу є досить послідовним.

Зокрема для bash, це задокументовано у розділі "Розширення назви файлів" у посібнику з bash; запустіть info bashі знайдіть "Розширення імені файлу" або подивіться тут .

Те, що це робиться оболонкою, а не окремими командами, має деякі цікаві (а іноді й дивовижні) наслідки. Найкраще в цьому - те, що обробка символів підказки відповідає (майже майже) всім командам; якби оболонка не робила цього, неминуче деякі команди не турбували б, а інші робили це тонко іншими способами, які автор вважав «кращими». (Я думаю, що в командній оболонці Windows є ця проблема, але я недостатньо знайомий з нею для коментарів.)

З іншого боку, складно написати команду перейменувати кілька файлів. Якщо ви пишете:

mv *.log *.log.bak

це, ймовірно, не вдасться, оскільки *.log.bakрозширюється на основі файлів, які вже є в поточному каталозі. Є команди, які роблять подібні речі, але вони повинні використовувати власний синтаксис, щоб вказати, як файли потрібно перейменовувати. Деякі команди (наприклад, find) можуть зробити власне розширення підстановки; Ви повинні навести аргументи для придушення розширення оболонки:

find . -name '*.txt' -print

Розширення підстановки символів оболонки повністю засноване на синтаксисі аргументу командного рядка та наборі існуючих файлів. На це не може вплинути значення команди. Наприклад, якщо ви хочете перемістити всі .logфайли до батьківського каталогу, ви можете ввести:

mv *.log ..

Якщо ви забудете ..:

mv *.log

і .logв поточному каталозі буде рівно два файли, він розшириться до:

mv one.log two.log

який буде перейменовувати one.logі клобувати two.log.

EDIT : І після 52 заявок, прийому та значка Гуру, можливо, я повинен насправді відповісти на питання в заголовку.

-dАбо --directoryваріант lsне сказати це тільки список каталогів. Це дозволяє йому перелічувати каталоги так само, як їх самі, а не їх зміст. Якщо ви даєте ім'я каталогу в якості аргументу ls, за замовчуванням він відображатиме вміст каталогу, оскільки це, як правило, те, що вас цікавить. Ця -dопція пропонує йому перелічити лише сам каталог. Це може бути особливо корисним у поєднанні із символами підстановки. Якщо ви введете:

ls -l a*

lsдасть вам довгий перелік кожного файлу, з якого починається ім’я a, та вмісту кожного каталогу, з якого починається ім'я a. Якщо ви просто хочете, щоб список файлів і каталогів, один рядок для кожного, ви можете використовувати:

ls -ld a*

що еквівалентно:

ls -l -d a*

Згадайте ще раз, що lsкоманда ніколи не бачить *персонажа.

Що стосується того, де це зафіксовано, man lsпокаже вам документацію для lsкоманди майже про будь-яку систему, схожу на Unix. У більшості систем на базі Linux lsкоманда є частиною пакету основних ядер GNU; якщо у вас є infoкоманда, info lsабо info coreutils lsви повинні дати вам більш чітку та вичерпну документацію. Інші системи, такі як MacOS, можуть використовувати різні версії lsкоманди і можуть не мати infoкоманди; для цих систем використовуйте man ls. І ls --helpбуде показано відносно коротке повідомлення про використання (117 рядків у моїй системі), якщо ви використовуєте реалізацію CoreNutil GNU.

І так, навіть експертам потрібно час від часу звертатися з документацією. Дивіться також цей класичний жарт .


8
@Thomas: a*розширюється до списку всіх файлів у поточному каталозі , імена яких починаються з a.
Кіт Томпсон

2
@Thomas: Або в будь-якому каталозі, який ви вказали:ls subdir/a*
Кіт Томпсон

1
Щоб дійсно побачити команду, виконану після розширення оболонки, echoвона. Тож якщо ви хочете знати, що відбувається, коли ви це робите ls a*, спочатку виконуйтеecho ls a*
Карлос Кампдеррос

1
або просто echo a*... оболонка все-таки робить глобальне розширення
Марно

2
@sendmoreinfo: Це залежить від оболонки та налаштувань. У csh та tcsh невдале розширення глобальної системи - помилка. У баші, shopt -s failglobвикликає таку саму поведінку. Налаштування, nullglobале не failglobспричиняє, наприклад, *nosuchfile*розширення до порожнього рядка.
Кіт Томпсон

27

Дивіться відповідь Кіта Томпсона; але щоб пояснити, чому ls --directory a*відображаються файли та каталоги: Цей --directoryпараметр не пригнічує файли, що не мають каталогів. Натомість, він перераховує каталоги як такі, тоді як інакше буде перераховано їхній вміст. Приклад:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo

3
цей приклад є більш переконливим із -Fваріантом
Глен Джекман

6

Щоб бути дуже чітким, це зафіксовано на сторінці керівництва ls (1) :

-d, - записи каталогів списку замість вмісту, і не перенаправляти символічні посилання

Чесно кажучи, "записи замість вмісту", ймовірно, можуть бути більш пояснювальними:

Якщо FILE - це каталог, покажіть сам запис каталогу, а не перераховуйте вміст цього каталогу. Якщо FILE є символічним посиланням, покажіть сам запис посилання замість файлу, на який вказує посилання.


Щоб бути педантичним, тоді як опція -d може бути пояснена (якщо недовговічною) на сторінці man, розширення аргументів та підстановка символів не зафіксовані на сторінці ls man, оскільки це зроблено оболонкою. Якщо ви вимкнули розширення назви файлів у своїй оболонці, "ls a *" покаже вам лише файл, який буквально названий "a *".
Джонні

Щоб бути педантичним, тоді як розширення оболонки відповідали інші респонденти, жоден з них не звертається до мізерного пояснення та того, як це може бути неправильно прочитане. Якщо ви хочете, щоб я повторив те, що вже було добре сказано, будь ласка, будьте більш прямими.
msw

4

Глобінг

Як було пояснено, розширення *(та подібні розширення) globв жаргоні Unix називається бінгом і, як правило, є функцією командного процесора (відомий як "оболонка" на мові Unix). Тому глобус можна використовувати і в багатьох інших місцях; введіть man 7 globв оболонці класичного дистрибутива Linux (або перегляньте це ), щоб дізнатися більше про globbing.

На початку Unix globфактично реалізовувалася окремою програмою під назвою /etc/glob(див. Сторінку 10 цього старого посібника UNIX для документації на це). В даний час це кодова програма, що постачається бібліотеками кодів, і зазвичай використовується оболонками. Джерело : Вікіпедія .

Довідники

Щодо ls -dсписку файлів, а також каталогів ...

Сторінка " lsman" пояснює, чому це відбувається, але з дуже лайливим поясненням. Ось ось спроба розширеного пояснення:

За замовчуванням lsперераховує вміст каталогів, коли їх імена, і буде робити те саме, що для посилань на каталоги. В -dопції означає, «коли дано ім'я (и) каталог (країна)» (які також можуть бути задані неявно з допомогою globБінга) , показує тільки _name_s каталогу (країна), але НЕ їх зміст. Аналогічно, якщо вони надаються (явно чи неявно ) ім'ям (ими) посилань на каталоги , покажіть ім'я файлу посилання, а не вміст каталогу, на який він посилається.

-dНаскільки я не можу сказати, цей варіант не має нічого спільного з якими предметами перелічено; це можна зробити (джерело: тут ) з find, наприклад , так: find . -maxdepth 1 -type d. Я не впевнений, чи є хороший спосіб зробити це лише з GNU ls. Ось кілька прикладів використання findкоманди.

Отже, підводячи підсумок: за замовчуванням lsвідображається вміст каталогів, коли дається ім'я їх шляху. -dзмінює цю поведінку, показуючи лише ім'я каталогу, як це було б зроблено для стандартного файлу.


3

Документація не говорить про те, що вона містить лише записи каталогу, а при отриманні lsімені каталогу вона містить список dir замість вмісту. Найкращий спосіб зрозуміти це на прикладі:

> {ice} ~ :10:47 % ls -l / 
total 97
drwxr-xr-x   2 root root  4096 May  3 00:27 bin
drwxr-xr-x   4 root root  1024 May  3 14:17 boot
drwxr-xr-x   2 root root  4096 Apr 29 13:44 cdrom
drwxr-xr-x  18 root root  4420 May  9 09:58 dev
...
lrwxrwxrwx   1 root root    33 May  3 14:16 vmlinuz -> boot/vmlinuz-3.9.0-030900-generic
lrwxrwxrwx   1 root root    29 May  3 11:07 vmlinuz.old -> boot/vmlinuz-3.8.0-19-generic
> {ice} ~ :10:47 % ls -ld /
drwxr-xr-x 25 root root 4096 May  3 14:16 /

2

Документація є частиною оболонки . Зокрема, оболонка виконує різні розширення та підстановки в певному порядку перед виконанням команди.

Послідовність розширень слів для сумісної оболонки Bourne є

  1. Тильда розширення
  2. Розширення параметрів
  3. Командна заміна
  4. Арифметичне розширення
  5. Розщеплення поля
  6. Розширення шляху
  7. Видалення лапки

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


1

Ключове слово, яке вам потрібно ( man bash), - "Розширення імені Pathname".


3
більше схожі на "Розширення імені Pathname" або "Generation File Generation". Пов’язане із "узгодженням шаблону", але не те саме.
Стефан Шазелас

@StephaneChazelas Дійсно, але "відповідність шаблону" є підрозділом "розширення імені шляху" на головній сторінці, тоді як "Генерація імен файлів" там взагалі не відбувається (лише в інформаційному документі).
Хоуке Лагінг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.