Arhn - архитектура программирования

Как получить только имя файла с Linux 'find'?

Я использую find для всех файлов в каталоге, поэтому я получаю список путей. Однако мне нужны только имена файлов. т.е. я получаю ./dir1/dir2/file.txt и хочу получить file.txt

28.03.2011

Ответы:


1

В GNU find для этого можно использовать параметр -printf, например:

find /dir1 -type f -printf "%f\n"
28.03.2011
  • Очевидно, что это ответ, но в нем отсутствуют детали. 20.09.2013
  • У меня не работает, когда я использую несколько типов файлов (переключатель -o) 14.02.2014
  • find: -printf: неизвестный первичный объект или оператор 15.05.2014
  • @Urchin Нет причин, по которым этого не должно быть, если у вас есть правильная логика (т.е. -o имеет более низкий приоритет, чем подразумеваемый -a, поэтому вы часто захотите сгруппировать свои -o аргументы) 29.07.2014
  • find ./ -name "*" -printf "%f\n" | xargs grep "searchName" Это не сработает, будет только напечатано: about.php: Нет такого файла или каталога grep: site-themes.php: Нет такого файла или каталога Или find ./ -name "*" | xargs grep "searchName" -printf "%f\n" все еще ошибка 05.10.2014
  • Я не думаю, что это правильный ответ. find -printf "%f\n" -exec echo {} \; показывает, что исходное имя файла передается вперед 23.11.2017
  • Ясно не хватает деталей, куда поместить имя целевого файла file.txt в команде. 27.05.2019
  • @SoulClinic Следовательно, предостережение "GNU" 09.02.2021

  • 2

    Если в вашей находке нет опции -printf, вы также можете использовать basename:

    find ./dir1 -type f -exec basename {} \;
    
    28.03.2011
  • Использование точки с запятой - еще один способ устранить неоднозначность: ... {} ';' 28.12.2012

  • 3

    Используйте -execdir, который автоматически сохраняет текущий файл в {}, например:

    find . -type f -execdir echo '{}' ';'
    

    Вы также можете использовать $PWD вместо . (в некоторых системах это не приведет к появлению дополнительной точки спереди).

    Если у вас все еще есть лишняя точка, вы также можете запустить:

    find . -type f -execdir basename '{}' ';'
    

    -execdir utility [argument ...] ;

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

    Когда используется + вместо ;, тогда {} заменяется максимально возможным количеством путей для каждого вызова утилиты. Другими словами, он напечатает все имена файлов в одной строке.

    23.10.2015
  • Я получаю ./filename вместо filename. В зависимости от ваших потребностей, это может подойти, а может и не подойти. 05.01.2017
  • @ user276648 Попробуйте использовать $PWD вместо .. 05.01.2017

  • 4

    Если вы используете GNU find

    find . -type f -printf "%f\n"
    

    Или вы можете использовать язык программирования, например Ruby (1.9+)

    $ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
    

    Если вам нравится решение bash (как минимум 4)

    shopt -s globstar
    for file in **; do echo ${file##*/}; done
    
    28.03.2011
  • Я был вдохновлен вашим ответом, чтобы помочь sleske: serverfault.com/a/745968/329412 11.08.2016

  • 5

    Если вы хотите выполнить какое-либо действие только против имени файла, использование basename может быть трудным.

    Например это:

    find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \; 
    

    будет просто отображать базовое имя /my/found/path. Не то, что нам нужно, если мы хотим выполнить с именем файла.

    Но тогда вы можете xargs получить результат. например, чтобы убить файлы в каталоге на основе имен в другом каталоге:

    cd dirIwantToRMin;
    find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm
    
    18.07.2013
  • не эхо - find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; 25.04.2018

  • 6

    На Mac (BSD find) используйте:

    find /dir1 -type f -exec basename {} \;
    
    03.11.2018

    7

    Как указывали другие, вы можете комбинировать find и basename, но по умолчанию программа basename будет работать только по одному пути за раз, поэтому исполняемый файл должен будет запускаться один раз для каждого пути (используя либо find ... -exec, либо find ... | xargs -n 1), что потенциально может быть медленным.

    Если вы используете параметр -a на basename, тогда он может принимать несколько имен файлов за один вызов, что означает, что вы можете затем использовать xargs без -n 1, чтобы сгруппировать пути вместе в гораздо меньшее количество вызовов basename, которые должны быть более эффективным.

    Пример:

    find /dir1 -type f -print0 | xargs -0 basename -a
    

    Здесь я включил -print0 и -0 (которые следует использовать вместе), чтобы справиться с любыми пробелами внутри имен файлов и каталогов.

    Вот сравнение времени между версиями xargs basename -a и xargs -n1 basename. (Для сравнения подобного с подобным, указанные здесь тайминги относятся к начальному фиктивному запуску, так что оба они выполняются после того, как метаданные файла уже были скопированы в кэш ввода-вывода.) Я направил вывод в cksum в обоих случаях, просто чтобы продемонстрировать, что результат не зависит от используемого метода.

    $ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
    2532163462 546663
    
    real    0m0.063s
    user    0m0.058s
    sys 0m0.040s
    
    $ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum' 
    2532163462 546663
    
    real    0m14.504s
    user    0m12.474s
    sys 0m3.109s
    

    Как видите, избежать запуска basename каждый раз значительно быстрее.

    22.05.2020
  • Читая ответ от @minusf более внимательно, я вижу, что на Mac basename будет принимать несколько имен файлов без каких-либо дополнительных аргументов командной строки. -a здесь используется в Linux. (basename --version говорит мне basename (GNU coreutils) 8.28.) 22.05.2020

  • 8

    -exec и -execdir медленные, xargs король.

    $ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
    f -exec basename {} \; | wc -l; \
    f -execdir echo {} \; | wc -l; \
    f -print0 | xargs -0 -n1 basename | wc -l; \
    f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
    f -print0 | xargs -0 basename | wc -l
    
         139
        0m01.17s real     0m00.20s user     0m00.93s system
         139
        0m01.16s real     0m00.20s user     0m00.92s system
         139
        0m01.05s real     0m00.17s user     0m00.85s system
         139
        0m00.93s real     0m00.17s user     0m00.85s system
         139
        0m00.88s real     0m00.12s user     0m00.75s system
    

    Также помогает параллелизм xargs.

    Как ни странно, я не могу объяснить последний случай xargs без -n1. Он дает правильный результат и самый быстрый ¯\_(ツ)_/¯

    (basename принимает только 1 аргумент пути, но xargs отправит их все (фактически 5000) без -n1. Не работает на linux и openbsd, только на macOS ...)

    Некоторые большие числа из системы Linux, чтобы увидеть, как -execdir помогает, но все же намного медленнее, чем параллельный xargs:

    $ alias f='time find /usr/ -maxdepth 5 -type d'
    $ f -exec basename {} \; | wc -l; \
    f -execdir echo {} \; | wc -l; \
    f -print0 | xargs -0 -n1 basename | wc -l; \
    f -print0 | xargs -0 -n1 -P 8 basename | wc -l
    
    2358
        3.63s real     0.10s user     0.41s system
    2358
        1.53s real     0.05s user     0.31s system
    2358
        1.30s real     0.03s user     0.21s system
    2358
        0.41s real     0.03s user     0.25s system
    
    11.02.2020
  • еще один момент: на openbsd в течение длительного времени find именно -execdir становится самым быстрым, поскольку создание новых процессов является относительно дорогостоящей операцией. 12.02.2020

  • 9

    Честно говоря, решения basename и dirname проще, но вы также можете проверить это:

    find . -type f | grep -oP "[^/]*$"
    

    or

    find . -type f | rev | cut -d '/' -f1 | rev
    

    or

    find . -type f | sed "s/.*\///"
    
    09.05.2020
  • Блин, rev, какой ловкий трюк! 29.05.2021

  • 10

    Я нашел решение (на странице makandracards), которое дает только самое новое имя файла:

    ls -1tr * | tail -1
    

    (спасибо Arne Hartherz)

    Я использовал его для cp:

    cp $(ls -1tr * | tail -1) /tmp/
    
    26.04.2013
  • Это вообще не отвечает на вопрос. 23.10.2015
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..