найдите и globbing (и подстановочные знаки)

Вы могли переключиться на lftp вместо того, чтобы использовать scp. Это дает Вам хороший последовательный интерфейс для передачи файлов по ftp, sftp и ssh включая автоматическое заполнение, которое Вы ищете и больше (т.е. подстановочные знаки).

lftp fish://user@machine

открывается соединение по ssh как Вы делают выше с scp. Много машин поддерживают sftp://также, который еще более хорош, по моему опыту.

10
09.11.2012, 23:35
3 ответа

Когда Вы вводите команду, которая включает неупомянутый шарик как .b* или *.e*, оболочка развернет это для Вас. Это происходит прежде find когда-либо видит его.

У Вас, вероятно, есть файлы как .bashrc, .bash_history, и т.д. в Вашем $HOME каталог. Таким образом, когда выполнено от $HOME, Ваша команда превращается find ... -execdir ls -d .bashrc .bash_history ... \;. Когда выполнено от других мест, .b* шарик ничему не соответствует, таким образом, через него проходят. Это все еще не работает, как find -exec ничего не делает с * шарики. Если Вы хотели, чтобы шарик был расширен для -exec, необходимо было бы вызвать оболочку, чтобы сделать это:

find ... -execdir sh -c 'echo globs: *' \;
8
27.01.2020, 20:01
  • 1
    Да, верный. Я предполагаю, что экранирован о поведении потому что выполнение вещей как find ... -name '*.txt' работы (да, да, одинарные кавычки) и дескрипторы те шарики правильно, но когда я передаю такие шарики -exec[dir], это перестало работать. Я сделал комментарий в своем сообщении об одинарных кавычках и никаких кавычках как в какой-то момент, я действительно пробовал все, так отбрасывание кавычек было первой вещью, которую я сделал, пытаясь выяснить, почему вещи перестали работать. Последний пример состоял в том, чтобы показать, что даже очевидная вещь не работала (да, я ожидал видеть .bashrc, .bash_history, и т.д.). –  Wojtek Rzepala 10.11.2012, 01:12
  • 2
    @WojtekRzepala -exec и -name работайте по-другому. -name действительно поддерживает шарики. –  jw013 10.11.2012, 02:00

Both the find command and the shell are capable of file globbing.

Это необычно -большинство команд НЕ способны выполнять подстановку и полностью полагаются на оболочку для расширения подстановок. Но find — это супер-пупер-мега-мощный пользовательский инструмент, с которым вы можете очень легко навредить себе!

Пример :при выполнении команды

   find /path -iname *.txt

Первое, что происходит, это попытка оболочки найти все файлы, соответствующие *.txt в текущем каталоге. Если он их находит, он заменяет имена всех соответствующих файлов для глобуса, а затем вызывает команду find. Команда find никогда не увидит глобус , если это произойдет, оболочка расширит его до несуществования.

Но если в текущем каталоге нет файлов, соответствующих глобусу, оболочка метафорически пожимает плечами и пропускает глобус без изменений для поиска. Таким образом, в этот момент команда find (, которая понимает подстановочные знаки, помните ), выводит имена всех файлов, которые она находит в /path, которые соответствуют подстановочным знакам.

Таким образом, использование globs таким образом означает, что find будет вести себя по-разному в зависимости от содержимого текущего каталога. Это почти наверняка не то, что вы хотите!

Чтобы оболочка не вмешивалась в подстановочные знаки до того, как find их увидит, экранируйте подстановочные знаки с помощью соответствующего метасимвола оболочки в кавычках. Обычно это просто означает помещение ваших глобальных строк в одинарные кавычки, как здесь

   find /path -iname '*.txt'

Remember, GLOBS ARE NOT REGEXES - the glob ".*" and the regex ".*" are very different and do not match the same strings!

18
27.01.2020, 20:01

Когда оболочка bashне может найти файл, соответствующий заданному шаблону подстановки, он оставляет этот шаблон нераскрытым. Это приводит к тому, что в вашей команде findlsполучает нерасширенный шаблон *.e*в качестве аргумента. Утилита lsне расширяет шаблоны подстановки имен файлов сама по себе, а полагается на то, что оболочка уже сделала это.

Это, скорее всего, ваша проблема с вашей последней командой find, которая, кажется, может работать правильно только из вашего домашнего каталога, возможно, потому, что ваш домашний каталог содержит файлы, соответствующие шаблону (.bashrc, например, соответствует .b*). Если шаблоны не соответствуют чему-либо в текущем каталоге, шаблон будет передан lsкак есть, а поскольку lsне расширяет шаблоны подстановки сам по себе, он не сможет перечислить какие-либо файлы.

Короче говоря, вы не можете вызвать lsнапрямую с помощью -execdirили -execи дать ему шаблон подстановки имени файла.

Кроме того, вы говорите, что хотите перечислить файлы, соответствующие *.e*, для «дальнейшей обработки». Я бы посоветовал не делать этого, а вместо этого выполнять эту обработку в самой команде find. Причина этого указана в вопросе/ответе "Почему перебор вывода find является плохой практикой? ".

Итак, вместо того, что вы сейчас делаете, подумайте

find. -type f -name md.tpr -exec bash -O nullglob -O dotglob -c '
    for pathname do
        dirpath=${pathname%/md.tpr}
        for e in "$dirpath"/*.e*; do
            # process "$e" here!
        done
    done' bash {} +

Предполагается, что md.tprявляется обычным файлом, который необходимо найти. Команда findнаходит пути ко всем этим файлам md.tprи загружает их пакетами во встроенный скрипт bash.Скрипт bashкороткий:

for pathname do
    dirpath=${pathname%/md.tpr}
    for e in "$dirpath"/*.e*; do
        # process "$e" here!
    done
done

Это просто берет заданные аргументы, извлекает компонент каталога каждого (, удаляя строку суффикса /md.tpr, которая, как мы знаем, присутствует, из пути )и циклически перебирает файлы, соответствующие *.e*в каждый каталог (с $e, содержащим путь к каждому совпадающему файлу, в свою очередь ).

Скрипт строки -запускается с установленными параметрами nullglobи dotglob, чтобы шаблон *.e*удалялся полностью, если он не совпадает, и чтобы шаблон соответствовал скрытому имена.

Немного больше информации об использовании -execс findможно найти в «Понимание опции -exec команды `find `».


Поскольку вы отметили этот вопрос тегом , вот как сделать то же самое в простом bashцикле (для этого требуется bashверсия 4 или более поздняя):

shopt -s globstar nullglob dotglob

for pathname in./**/md.tpr; do
    dirpath=${pathname%/md.tpr}
    for e in "$dirpath"/*.e*; do
        # process "$e" here!
    done
done

Помимо отсутствия каких-либо проверок того, являются ли сопоставленные md.tprфайлы обычными файлами или нет, это должно выглядеть очень похоже на скрипт в строке -, вызванный findвыше. Параметр оболочки globstarв bashвключает глобус **, который «рекурсивно» сопоставляется с подкаталогами.

Я ожидаю, что это будет немного медленнее, чем использование find, но это может оказаться более удобным способом написания кода.

0
27.01.2020, 20:01

Теги

Похожие вопросы