Как использовать `find` для перехода в каталог этого файла


11

Я хочу найти файл, а затем ввести каталог, содержащий его. Я пытался, find /media/storage -name "Fedora" | xargs cdно, конечно, я is not a directoryошибка.

Как мне ввести его родительский каталог с помощью однострочной команды?


1
А что, если есть несколько файлов из разных мест?
Сергей Колодяжный

@ Serg Я ищу файл Fedora * .iso, и я знаю, что есть только один. Я думаю, что если бы их было больше одного, они бы вошли в первое направление
Hrvoje T

В bash shopt -s globstarвы могли бы cd /media/storage/**/Fedora, но это не останавливает оценку глобуса при первом совпадении (так что это медленнее, чем решение SteelDriver. Для интерактивного использования я обычно использую мышь и копирую / вставляю имя каталога, (и alt + backspace по мере необходимости, чтобы убрать задние компоненты пути, которые я не хотел), но если вы будете делать это много, я думаю, что стоит сделать функцию оболочки.
Питер Кордес

1
Кстати, xargs cdне может работать. cdможет работать только как встроенная оболочка, потому что она должна изменять контекст самой оболочки. Нет никакого способа, которым xargsдочерний процесс может сделать это. IDK, если это то, что вы имели в виду под «конечно», или если путь, который findпечатается, содержит пробелы, разделенные xargs, поскольку вы не использовали, -d \nили что-то еще. Или find -exec {} \;.
Питер Кордес

примечание: вы не можете так бегать cd. cdэто встроенный bash, если бы cdэто была отдельная команда, то он изменил бы (свой собственный) dir, а затем завершил работу (вернул вас в оболочку, которая находится в том же состоянии, что и раньше, без изменения dir).
ctrl-alt-delor

Ответы:


14

По крайней мере, если у вас есть GNU find, вы можете использовать, -printf '%h'чтобы получить каталог

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Так что вы могли бы сделать

cd "$(find /media/storage -name "Fedora" -printf '%h' -quit)"

Значение -quitдолжно предотвращать множественные аргументы, если cdв случае совпадения более одного файла.


1
-quitтакже не обязательно поддерживается. В NetBSD это называется -exit, см. Unix.stackexchange.com/a/62883/117599
phk

2
Если нет printf, вы могли бы вместо этого использовать -exec dirname?
Парень

@ Хорошая идея, да, звучит так, будто это тоже должно сработать
Steeldriver

6

Похоже на решение Steeldriver, но использует -execdir(если вы findего поддерживаете, например, GNU или FreeBSD find) в сочетании с pwd:

cd "$(find /media/storage -name "Fedora" -execdir pwd \; -quit)"

-quitявляется необязательным в том случае, если есть только один результат, и сканирование всего каталога не представляет проблемы. В NetBSD он есть, -exitа в OpenBSD его нет.


А для чего \;?
Hrvoje T

1
@HrvojeT Точно так же, как -execэто говорит findо конце параметров для выполнения команды. Но так как мы хотим вызвать pwdбез параметров здесь, мы ставим \;сразу после него.
phk

Есть ли findреализации, которые поддерживают execdir, но нет -printf %h? Кажется маловероятным для меня. К сожалению, POSIX не требует ни того, ни другого: /
Питер Кордес

1
@PeterCordes FreeBSD find: freebsd.org/cgi/man.cgi?find%281%29 (только что подтвердил это при установке FreeBSD 11.)
phk

@PeterCordes То же самое для NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-current ) и OpenBSD ( man.openbsd.org/OpenBSD-current/man1/find.1 ). Последний не поддерживает -quit/ -exitвообще, хотя.
PhK

5

Вы можете заставить find запускать новую оболочку в каталоге, который он находит.

exec find /media/storage -name "Fedora" -execdir "$SHELL" \;

после чего текущим каталогом будет файл с именем Fedora. ;)

Очевидно, что это делает только то, что вы хотите, если вы вводите команды в интерактивном режиме.


4

С zsh:

cd /media/storage/**/Fedora([1]:h)

чтобы cdв каталог первого (в алфавитном порядке) , который содержит файл с именем Fedora.

  • **: любой уровень каталогов (по умолчанию скрытые каталоги опущены, используйте Dспецификатор glob, чтобы включить их)
  • [1]: только первый
  • :h: head модификатор: возьми dirname.

В отличие от этого cd "$(find ...)", это также работает, если имя каталога заканчивается символом новой строки. Еще одним преимуществом является то, что вы получите сообщение об ошибке отсутствия совпадения, когда нет соответствующего каталога (в то время как в большинстве оболочек cd ""ничего не делается молча).

Недостатком является то, что он будет ползти, /media/storageпрежде чем вернуться.


В bash cdс несколькими аргументами в любом случае просматривается только первый аргумент, поэтому он cd $(dirname /media/storage/**/Fedora)будет работать (с shopt -s globstar), если в пути нет пробелов. Для того, чтобы получить его цитировали правильно, я думаю, что массив Баша проще: target=(/media/storage/**/Fedora); cd "${target%/*}". Но в этот момент было бы быстрее использовать мышь для копирования / вставки результатов поиска, а не интерактивно.
Питер Кордес

2
@PeterCordes, многие dirnameреализации не будут принимать более одного аргумента. Обратите внимание, что это не пробелы , это любой символ в настоящее время $IFS(пробел, табуляция и новая строка по умолчанию) и символы подстановки. Обратите внимание , что ли bash«s cdбудет принимать более одного аргумента зависит от того, как он был составлен ( CD_COMPLAINSв config-top.h). Можно представить, что в будущих версиях bashтакже будет реализована функция двух аргументов, как в zsh.
Стефан

Благодарю. Я только что посмотрел на справочную страницу GNU coreutils dirname. Версия dirname в любом случае ужасна; Я упомянул это только как то, что вы можете попробовать в интерактивном режиме, если это сработало. Моя версия на основе массива не страдает ни от одной из этих проблем, поскольку "${target%*/}"расширяется только до первого элемента массива (с /Fedoraудаленным). Я думаю, что версия полностью устойчива к любым возможным символам в пути.
Питер Кордес
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.