ls вміст каталогу ігноруючи символьні посилання


17

У мене є каталог, в якому я хотів би перерахувати весь вміст (файли та підкаталоги), не показуючи символічні посилання. Я використовую утиліти GNU в Linux. lsВерсія 8,13.

Приклад:

Повний список каталогу:

~/test$ ls -Gg
total 12
drwxrwxr-x 2 4096 Jul  9 10:29 dir1
drwxrwxr-x 2 4096 Jul  9 10:29 dir2
drwxrwxr-x 2 4096 Jul  9 10:29 dir3
-rw-rw-r-- 1    0 Jul  9 10:29 file1
-rw-rw-r-- 1    0 Jul  9 10:29 file2
lrwxrwxrwx 1    5 Jul  9 10:29 link1 -> link1
lrwxrwxrwx 1    5 Jul  9 10:30 link2 -> link2

Що я хотів би отримати

~/test$ ls -somthing (or bash hack)
total 12
dir1 dir2 dir3 file1 file2

ПРИМІТКА. Моя основна мотивація - робити рекурсивний греп (GNU grep 2.10) без наступних посилань.

Відповіді:


28

Для зазначеного питання ви можете використовувати find:

find . -mindepth 1 ! -type l

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

mindepth 1полягає лише в тому, щоб пропустити .запис поточного каталогу. М'ясо його є поєднанням -type l, що означає "символічна ланка", і !, що означає заперечення наступного тесту. У поєднанні вони відповідають кожному файлу, який не є символьним посиланням. Тут перераховані всі файли та каталоги рекурсивно, але ніяких посилань немає.

Якщо ви просто хочете регулярні файли (а не каталоги):

find . -type f

Щоб включати лише прямих дітей цього каталогу, а не всіх інших рекурсивно:

find . -mindepth 1 -maxdepth 1

Ви можете комбінувати ці (та інші) тести разом, щоб отримати список потрібних файлів.

Щоб виконати певний grepфайл у кожному файлі, що відповідає тестам, які ви використовуєте, використовуйте -exec:

find . -type f -exec grep -H 'some pattern' '{}' +

Волю '{}'буде замінено на файли. +Треба сказати , findваша команда буде зроблено. Цей параметр -Hпримушує grep відображати ім'я файлу, навіть якщо він трапляється працювати з одним відповідним файлом.


У ньому не відображаються файли, у яких знайдено візерунок.
TheMeaningfulEngineer

Ось за що ви бачитесь grep(див. Останній абзац).
Майкл Гомер

Я не працюю для мене. Він просто виводить знайдені шаблони без імені файлу, де його було знайдено.
TheMeaningfulEngineer

2
Використовуйте grep -H, якщо у вас є (див. man grep), Або іншим способом grep 'pat' '{}' /dev/null ';'обманути його на думку, що у вас є декілька файлів, якщо їх немає.
Майкл Гомер

1
+не відповідає цій вимозі у виродженому випадку, коли в кінці залишився лише один файл або один файл.
Майкл Гомер

17

Або, простіше:

ls -l | grep -v ^l

Пояснення

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

grep -v ^lозначає відфільтрувати ( -v) рядки, які починаються з ( ^) an l.


Це чудово працює, але як отримати лише імена папок? Я хочу використовувати це уfor i in
Лука

Чи можете ви пояснити цей код?
abg

Врахуйте , що це рішення не працює , якщо ви ommit -lв ls. Отже, це не буде працювати, як очікувалося:ls | grep -v ^l
stamster

@Luka Ви не переходите на вихід find, див. Unix.stackexchange.com/questions/321697
Kusalananda

1
@abg - я додав пояснення. Сподіваюся, це допомагає.
Джефф

7

Починаючи з версії 2.12, -rопція grep GNU не переносить символічні посилання, якщо ви не вкажете їх вручну:

-r, --рекурсивний

Читайте всі файли в кожному каталозі, рекурсивно, дотримуючись символічних посилань, лише якщо вони знаходяться в командному рядку. Це еквівалентно опції -d рекурсу.

-R, --відповідно-рекурсивний

Читайте всі файли в кожному каталозі, рекурсивно. Дотримуйтесь усіх символьних посилань, на відміну від -r.


Яка версія grep така. У мене -R, -r, --recursive Read all files under each directory, recursively; this is equivalent to the -d recurse option.в 2.10
TheMeaningfulEngineer

grep (GNU grep) 2.14
tijagi

5

У zsh, це буде легко завдяки глобальним класифікаторам :

grep -- PATTERN **/*(.)

Шаблон **/перетинає підкаталоги рекурсивно. Класифікатор глобу .обмежує відповідність звичайним файлам.

Без zsh використовуйте find(див. Відповідь Майкла Хорнера ). І в цьому конкретному випадку GNU grep може робити все, що завгодно (це саме те, що grep -rробиться) - але тільки з версії 2.12, більш ранні версії йшли за символічними посиланнями.


2

Ви можете використовувати $LS_COLORSдля цього. Якщо ваша версія lsпідтримує вказівку кольорів за допомогою цієї змінної, ви можете визначити вихід на тип файлу. Це вбудована поведінка і дуже настроюється. Тому я створив кілька файлів для демонстрації цього:

for f in 9 8 7 6 5 4 3 2 1
    do touch "${f}file" && 
    ln -s ./"${f}file" ./"${f}filelink"
done

Тому зараз я зроблю:

LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \
ls -1 --color=always | cat

###OUTPUT###
1file


HERE_THERE_BE_A_LINK>>1filelink@
2file


HERE_THERE_BE_A_LINK>>2filelink@
3file

...
HERE_THERE_BE_A_LINK>>8filelink@
9file
...

І нулі теж є ...

LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \
ls -1 --color=always | sed -n l
1file$
$
$
\000HERE_THERE_BE_A_LINK>>\0001filelink@$
2file$
$
$
\000HERE_THERE_BE_A_LINK>>\0002filelink@$
3file$
...

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

LS_COLORS='rs=:no=//:lc=:rc=:ec=//:'$(
set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=/$fc//:"
done) ls -l --color=always | cat

Його вихід у моєму домашньому каталозі виглядає приблизно так:

total 884
///-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 /fi//1/
//drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 /di//Desktop//
//-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 /fi//Terminology.log/
//-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 /fi//new
file/
//lrwxrwxrwx 1 mikeserv mikeserv     10 Jul 11 04:18 /ln//new
file
link/ -> /fi//./new
file/
//-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 /ex//script.sh/*
//-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 /fi//shot-2014-06-22_17-10-16.jpg/
//-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 /fi//target.txt/

Ви можете це запустити cat -Aі з єдиною різницею, з якою ви зіткнетеся, це те, що ви побачите $нові рядки - немає недрукованих символів, введених ls --color=alwaysцією конфігурацією - лише те, що ви бачите тут.

ls вставляє його за замовчуванням термінальні втечі так:

${lc}${type_code}${rc}FILENAME${lc}${rs}${rc}

... де значення за замовчуванням для $lc (зліва від коду) , $rc (справа від коду) та $rs (скинути) :

 \033 - ESCAPE
 m - END ESCAPE
 0 - reset 

... відповідно. ${type_code}використовується для встановлення різних fi (звичайний файл - скидання за замовчуванням) , di (каталог) , ln (посилання) та всіх інших типів файлів, про які я знаю. Існує також $no (нормальний), який також за замовчуванням не встановлений і який тут представлений символом //на початку кожного рядка. Мій простий маленький IFS=:блок працює просто, вставляючи ім’я для кожного конфігуруючого також у якості власного значення та додаючи косу рису або два - хоча \0байти NUL також будуть.

За замовчуванням lsтакож буде вставлений один $rsбезпосередньо перед його першим результатом $lc- але це не точно представлено тут. У цьому випадку я вказав $ec (кінцевий код), на який стоїть у $rsвсіх випадках - коли він вказаний, ви не отримуєте зайвого $rsміж $noі, ${type_code}як інакше - він відображається лише відразу після імені файлу та одного разу на початку виводу - як ви бачите на одному додатковому косому кутку на чолі рядка перший.

Ось фрагмент з мого власного $LS_COLORS

printf %s "$LS_COLORS"

rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:\
so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:\
or=40;31;01:su=37;41:sg=30;43:ca=30;41:\
tw=30;42:ow=34;42:st=37;44:ex=01;32:\
*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:...

І, по правді, мій маленький злом оболонки, мабуть, надто складний - є широко доступний інтерфейс для призначення цих значень. Спробуйте dircolors -pв своєму кліпі і info dircolorsдля отримання додаткової інформації про це.

Ви можете загортати назви файлів у довільних рядках. Ви можете прокоментувати їх, якщо хочете. Ви можете вказати подібну поведінку, засновану лише на розширенні файлу. Адже насправді не так багато можна вказати.

Зараз я не просто все це складаю - я дізнався про це після випадкового натикання на вихідний код .

З цією конкретною конфігурацією lsвипромінюється:

  1. $no - один раз на запис на початку кожного запису

  2. ${type_code}- один раз безпосередньо перед кожним іменем файлу, щоб включити абревіатуру типу файлу, яка завжди зустрічається в тому ж рядку, що і 7 полів, розмежованих пробілом, після $no або відразу після ->позначення цілі символічного посилання.

  3. $ec - один раз безпосередньо перед першим рядком, а потім лише один раз одразу після кожного імені файлу.

  4. Усі інші значення порожні.

Далі йде з нульовим обмеженням ls, і на цей раз я буду використовувати cat -A, хоча без нього це виглядатиме так само, як і останній приклад:

LS_COLORS='rs=:no=\0//:lc=:rc=:ec=\0//:'$(
set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=/$fc//\0:"
done) ls -l --color=always | cat -A

total 884$
^@//^@//-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 /fi//^@1^@//$
^@//drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 /di//^@Desktop^@///$
^@//-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 /fi//^@Terminology.log^@//$
^@//-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 /fi//^@new$
file^@//$
^@//lrwxrwxrwx 1 mikeserv mikeserv     10 Jul 11 04:18 /ln//^@new$
file$
link^@// -> /fi//^@./new$
file^@//$
^@//-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 /ex//^@script.sh^@//*$
^@//-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 /fi//^@shot-2014-06-22_17-10-16.jpg^@//$
^@//-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 /fi//^@target.txt^@//$

Отже, щоб надійно видалити всі символічні посилання зі -lсписку онг, як цей, ви можете зробити просту зміну:

LS_COLORS='rs=:no=//:lc=:rc=:ec=/ :'$(
set -- di fi mh pi so do bd cd or su sg ca tw ow st ex
for fc do printf %s "$fc=$fc/:"
done)ln=///: ls -l --color=always | sed ':ln
\|///|{N;\|\n//|!bln};s|.*//||'

Мої результати після запуску виглядають як ...

total 884
-rw-r--r-- 1 mikeserv mikeserv    793 Jul  9 11:23 fi/1/ 
drwxr-xr-x 1 mikeserv mikeserv    574 Jun 24 16:50 di/Desktop/ /
-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 fi/Terminology.log/ 
-rw-r--r-- 1 mikeserv mikeserv      0 Jul  6 11:24 fi/new
file/ 
-rwxr-xr-x 1 mikeserv mikeserv    190 Jun 22 11:26 ex/script.sh/ *
-rw-r--r-- 1 mikeserv mikeserv 433568 Jun 22 17:10 fi/shot-2014-06-22_17-10-16.jpg/ 
-rw-r--r-- 1 mikeserv mikeserv     68 Jun 17 19:59 fi/target.txt/ 

Використовуючи команду, подібну до тієї, яку я виконую вище:

LSCOLORS=...$(...)fc1=///:fc2=///: ls ... | sed ...

... (де fc1і fc2переліки файлів перераховані після set --в підпакеті) повинні служити надійному видаленню будь-яких поєднань типів файлів, які ви хочете отримати з lsвиводу незалежно від будь-яких символів, які можуть містити назви файлів.


Хе, приємно, +1 за оригінальність. Здається, задихається в каталогах, однак вони надруковані накресленим кольором коду ANSI. Як би там не було, ви можете додати пояснення, як це працює? Може бути , пояснити , що lc, nc, і т.д.?
тердон

@terdon - Вони друкуються тільки з ANSI вислизає вже встановлені у вашому середовищі і чи скомпільовано як значення за замовчуванням для ls«S di=значення. Вам потрібно буде додати di=:до var, щоб скасувати це - і для всіх інших. Це те, що я маю на увазі під api - ви звертаєтесь до кожного типу файлів, але ви маєте адресувати інтерфейс однаковий у всіх випадках. Тож встановити lnодин спосіб та ігнорувати параметри diза замовчуванням не вийде. Є також багато типових значень, зібраних також ... Хм. Ваші запитання про lcі ncта речі справжні - повністю - я вже зробив це днями. Я зв’яжу це, я думаю.
mikeserv

Так, тож мені доведеться завжди вказувати всі можливі типи файлів або перевіряти, що є перед вами? Добре, дякую.
тердон

@terdon - дивіться мою редагування просто зараз - вона робить це все в пару рядків оболонки, вказуючи кожен тип за назвою типу і надійно розмежовуючи кожне ім’я файлу. Не введено також друкованих матеріалів. І для цього все-таки є апі - це dircolors. Він зчитує конфігураційний файл і видає evalзначення var, зручне для оболонки . Це досить просто - але так само кілька рядків там. У будь-якому випадку, якщо ви хотіли скористатися, dircolorsви просто збережіть два різні файли і позовуйте його таким чином. Крім того, я показав вам днями, як робити одночасно з \0роздільниками NUL як частину кожної послідовності втечі.
mikeserv

@terdon - Я намагався зробити більш зрозумілим, як легко встановити всі значення, які можуть бути складені - я думаю, що я отримав їх усіх, можливо, занадто багато ... LS_COLORS='rs=:no=\0//:lc=:rc=:ec=\0//:'$( set -- di fi ln mh pi so do bd cd or su sg ca tw ow st ex; for fc do printf %s "$fc=/$fc//\0:"; done) ls -l --color=always | cat -A
mikeserv

0

Відповідь вище призводить до наступного:

 ls -1F | grep -i "/"

Як не дивно, якщо залишити команду 1 з ls все ще дає список.


1
Чому grep -i? Це не так, як якщо це /може бути верхній або нижній регістр. lsза замовчуванням до формату noe-column, коли вихід не є терміналом (тут це труба).
Кусалаланда

-2

Спробуйте це:

ls | grep -v " -> "

2
Це не вдасться з різних причин, наприклад, у файлі під назвою a -> b. Він також не матиме назв файлів з новими рядками та іншими дивацтвами. Будь ласка, прочитайте це, чому розбір ls - це погана ідея.
тердон

@terdon Є більш фундаментальні причини, чому це не вдасться. Або lsце псевдонім ls -l, і це повертає стовпці перед назвою файлу, або його немає, і це не робить нічого особливого щодо символічних посилань.
Жил 'ТАК - перестань бути злим'

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

@mikeserv Я знаю, я знаю. Однак пояснення того, як це зробити безпечно, займає кілька сотень рядків, як ви самі продемонстрували. На сьогоднішній день ця відповідь страждає від усіх небезпек розбору і ОП явно не усвідомлює їх.
тердон

@terdon - lsне збирається їсти своїх дітей чи нічого - це лише програма. Якщо ви не поясните це , знадобиться кілька сотень, щоб пояснити це, і ще кілька сотень пояснити, чому кілька сотень рядків, з якими ви щойно пов’язані, помиляються. І окрім цього - це лише два рядки:LS_COLORS='lc=:rc=:ec=:ln=\n\n\0HERE_THERE_BE_A_LINK>>\0:' \ ls -1 --color=always | cat
mikeserv

-3

Спробуйте цю команду: ls -p | grep -v @


Ні, списки посилань.
TheMeaningfulEngineer

@Alan: k спробуйте цеfind -type f
таким чином

1
-1 тому що: i) -pщойно додає косу рису до каталогів, ви шукаєте -Fii) ваша findальтернатива не буде перераховувати каталоги та iii) будь ласка, протестуйте свої відповіді перед публікацією.
terdon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.