Виключіть каталоги в пошуку пошуку


14

Пошук із locateшляхами знаходження у файловій системі.
Часто ви апріорі знаєте, що вас цікавлять або файли, або лише каталоги.
Пошук "знайти" часто повертає багато результатів. Було б корисно включити в результат лише один із типів, оскільки це допомагає скоротити вихід.

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

Наведений нижче приклад - справжній світовий випадок, а не незвичайний:

$ locate --regex --basename "xfce4-keyboard-overlay$"
/usr/local/bin/xfce4-keyboard-overlay
/usr/local/share/xfce4-keyboard-overlay

Гаразд, ми щось знайшли! Але ... файли чи каталоги?

$ file /usr/local/bin/xfce4-keyboard-overlay 
/usr/local/bin/xfce4-keyboard-overlay:   bash script

Отже, це файл ...

$ file /usr/local/share/xfce4-keyboard-overlay
/usr/local/share/xfce4-keyboard-overlay: directory

а другий - ні.

Ця двозначність робить важкі для читання довгі списки шляхів, тому було б дуже приємно фільтрувати каталоги, наприклад, використовуючи параметр "comman line" для locate.

Чи існує щось подібне? Навіть якщо фільтр для каталогів відокремлений від locate?

Принаймні, можна використати скрипт для ітерації всіх імен файлів, щоб перевірити - що може бути повільним.

Відповіді:


3

З zsh:

print -rl ${(0)^"$(locate -0 ...)"}(N.)

(0)це прапор розширення параметра, який розбивається на символи NUL (як ми використовуємо locate -0), скорочено (ps:\0:).

З ^, замість додавання (N.)в кінці масиву, ми додаємо його до кожного елемента.

(N.)є глобальним класифікатором, .щоб відповідати лише звичайним файлам, Nщоб видалити елемент, якщо він не відповідає (не існує або не є звичайним файлом, або ми не можемо перевірити). Ви також можете використовувати, ^/а не .для узгодження не-каталогів, а не лише звичайні файли.

print -rlдрукує кожен аргумент необроблений в окремому рядку .

Ви можете використовувати будь-які zshглобальні класифікатори, але зауважте, що замовлення не матиме жодного ефекту, оскільки ми розширюємо один глобул на файл, тому для кожного сортування є лише один файл.

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


3

Це приблизно так само неелегантно, як інші відповіді, але, можливо, менш неефективно:

locate --regex --basename "xfce4-keyboard-overlay$" | 
        while IFS= read -r f; do [ -f "$f" ] && printf "%s\n" "$f"; done

(розбита на два рядки для читабельності). Вищеописане буде обробляти імена, що містять пробіли. IFS=, Як видається, необхідно обробляти імена з трейлинг простору, і, звичайно ж , -rдозволяє обробляти зворотні Слеш.

Підхід "давайте locateв щось" може бути приречений на невдачу, якщо є імена шляхів, що містять нові рядки.


Для отримання додаткової інформації про IFS, читання sh(1)або bash(1) (шляхом введення man shабо man bashв * NIX системи, і / або читати його тут , тут , тут , і / або тут ). Потім прочитайте « Розуміння IFS та Bash»: читайте рядок за рядком, з IFS на обміні стеками (зосередьтеся на відповідях більше 5 голосів), і якщо у вас все ще не вистачає, перегляньте IFS у результатах пошуку Вікі та IFS Грега на Вікні Bash Hackers (не на Exchange Stack).


чи можете ви додати трохи інформації про те, що whileозначає "IFS =" після вашої заяви?
Роберт


зворотна косої риски все ще буде проблемою з багатьма реалізаціями ехо. Ви повинні використовувати printfдля довільних даних .
Стефан Шазелас

можливо, ви зможете вирішити проблему з новими рядками, скориставшись параметром "--null" locateі доповнити так, readяк пропонується тут, transnum.blogspot.ie/2008/11/…
robert

@ StéphaneChazelas: Добре. Виправлено.
G-Man каже: «Відновіть Моніку»

2
locate --null --regex --basename "xfce4-keyboard-overlay$" |
  xargs -r0 sh -c 'find "$@" -prune ! -type d' sh

Насправді це навіть брудніше, ніж виглядає ... але гарна натхнення. Давайте зробимо вигляд, що це псевдокод, тоді це корисно :)
Volker Siegel

1
@Volker: Я погоджуюся, що це погано: у вашому прикладі буде вказано перелік /usr/local/share/xfce4-keyboard-overlay та кожен його підкаталог . Додавання -maxdepth 0допомагає.
G-Man каже: "Відновіть Моніку"

Іде ще краще ...: D locate --regex --basename "xfce4-keyboard-overlay$" | xargs -I % sh -c "test -d % && echo %"
FloHimself

1
Використання xargsз findбуло гарною ідеєю, я її відредагував, щоб зробити її надійною. Сподіваюся, ви не заперечуєте.
Стефан Шазелас

1

xargsповторить команду для кожного рядка, якщо ви вкажете -L 1або -iпараметр.

Дивіться тут

$ locate --regex --basename "xfce4-keyboard-overlay$" | xargs -i bash -c '(test -d "{}" && echo "{}")'

Щоправда, це поштовх нової оболонки для кожного файлу, але це має перевагу бути приємною та компактною.

EDIT: Я не був дуже задоволений цією відповіддю, тому що це натискання нової оболонки для кожного файла. Це має мати лише два процеси:

$ locate --regex --basename "xfce4-keyboard-overlay$" | xargs -i echo 'test -d "{}" && echo "{}"' | bash

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


3
Цей тільки перезавантажив мою машину (був файл, який називався, /home/evil/$(reboot)/xfce4-keyboard-overlayі я безглуздо запустив це як root).
Стефан Шазелас

2
@ StéphaneChazelas +1 за мужність запустити "випадковий кодез з інтернетів" як root;) (scnr)
Volker Siegel

0

Мої два центи:

while IFS= read i; \
do \
  if [ -f "$i" ]; \
  then \
    echo "$i"; \
  fi; \
done < <(locate --regex --basename "xfce4-keyboard-overlay$")

Це більш-менш те, як це зробив G-Man у поєднанні з заміною процесу.


Насправді це так чи інакше, як я це робив, у поєднанні з підстановкою процесу, мінус можливість обробляти назви файлів, які містять зворотні косої риси або мають пробіли білого кольору. Також зауважте, що в заголовку питання написано "виключити каталоги", і ця відповідь включає лише каталоги.
G-Man каже: "Відновіть Моніку"

Вибачте. Моя помилка. Виправлено.
Трістан Сторч

-1

Що робити , якщо ви об'єднаєте locateз fileі grep? ...

$ for f in `locate --regex --basename "xfce4-keyboard-overlay$"`; do file $f; done | grep -vi directory

Я не тестував, але думаю, що це може бути повільним, оскільки це створює процес fileдля кожного окремого шляху. Зауважте, що часто знайдено багато рядків результатів пошуку. Мій поточний тест шукає "gnome", даючи приблизно 73000 шляхів для тестування.
Волкер Зігель

2
@Volker: Це гірше, ніж це: для кожного $fфайлу fileпрограма відкриє цей файл і прочитає з нього . Це дуже дорого, коли все, що вам потрібно зробити - це stat(). ………… Також це дасть помилкові результати для файлів, які містять „каталог” у своїх іменах (наприклад, „phone_directory“). ... ... ... ... ... (Крім того , for f in `…`; do …синтаксис не може обробляти імена , що містять пробіли.)
G-Man говорить 'відновило Моніки'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.