Странная ошибка «Нет такого файла» с «xargs» и «file»

Я хотел бы получить MIME-тип всех файлов в текущем каталоге. Почему это не работает? Я тестировал bash на OSX или Linux. «file» жалуется, что он не может найти файл, но если я запустил его с тем же самым путем, он работает.

$ find . -type f | xargs -n 1 -I FILE echo $(file --mime-type -b FILE) ERROR: cannot open './foo.txt' (No such file or directory) ... $ file --mime-type -b ./foo.txt text/plain 

Конечно, в реальном мире я не просто «отгоняю» ответ, мне нужно использовать строку типа MIME в другой команде.

  • stdin, stderr, перенаправление и журналы
  • bash добавляет дополнительные одинарные кавычки
  • Заменить номер CD в теге MP3 ID3
  • Почему моя петля над выходом ls не работает?
  • Прочитайте вывод команды в переменной
  • Список файлов, созданных по воскресеньям
  • Это самое простое, что я мог бы решить эту проблему. Думаю, я не понимаю что-то о xargs имени файла xargs ?

  • Эхо-список процесса не работает
  • Задания подобны командам с статусом выхода, за исключением случаев, когда есть замена команды?
  • Как переименовать на фиксированную длину
  • Завершить второй (параллельный) процесс, если первый из них завершен
  • Расширение «$ @» для пользовательских переменных
  • Как читать первую и последнюю строку от выхода cat?
  • 3 Solutions collect form web for “Странная ошибка «Нет такого файла» с «xargs» и «file»”

    Командная подстановка $(file --mime-type -b FILE) выполняется оболочкой перед передачей xargs , поэтому вы не видите, что вам нужно. Ответить $(file --mime-type -b FILE) и передать его в bash -c через xargs

     find . -type f | xargs -n 1 -I FILE bash -c 'echo $(file --mime-type -b FILE)' 

    Здесь нет необходимости использовать xargs . Просто используйте переключатель find -s -exec .

     $ find . -type f -exec file --mime-type -- {} + 

    Примеры

    вывод file умолчанию

     $ find 8* -type f -exec file --mime-type -- {} + | tail -5 89999/sample10.txt: text/plain 89999/sample2.txt: text/plain 89999/sample4.txt: text/plain 89999/sample6.txt: text/plain 89999/sample9.txt: text/plain 

    file -b вывод

     $ find 8* -type f -exec file --mime-type -b -- {} + | head -5 application/x-empty text/x-perl text/plain text/plain text/plain 

    альтернативы

    Это всего лишь FYI, но есть еще одна команда под названием mimetype которую вы также можете использовать для того, чтобы сделать то же самое, что и file --mimetype . Эта команда является частью этого пакета в Fedora, perl-File-MimeInfo и работает аналогично:

     $ find 8* -type f -exec mimetype -- {} + | tail -5 89999/sample10.txt: text/plain 89999/sample2.txt: text/plain 89999/sample4.txt: text/plain 89999/sample6.txt: text/plain 89999/sample9.txt: text/plain 

    Более сложный exec

    Учитывая, что вы задавались вопросом о том, что «делать больше, чем просто эхо …», и поскольку вы пытаетесь использовать xargs я собираюсь сделать вывод, что вы думаете, что вам нужно будет сделать более подробную информацию с xargs .

    Но если вы используете find , это, как правило, не самый лучший способ. Вместо этого вы можете использовать find , а затем в find -s -exec коммутаторе вызывать оболочку и делать здесь более сложные вещи, а не пытаться уговорить xargs делать это сложнее.

     $ find . -type f -exec sh -c ' cmd1; cmd2; file --mime-type -b "$@"; cmd3; cmd4; ' sh {} \; 

    ПРИМЕЧАНИЕ. Я перешел от использования терминатора + который передает несколько аргументов в file --mime-type ... to \; который проходит один за раз.

    пример

     $ find 8* -type f -exec sh -c ' echo -n "mime-type: "; file --mime-type -b "$@" ' sh {} \; |& tail -10 mime-type: text/plain mime-type: text/plain mime-type: text/plain mime-type: text/plain mime-type: text/x-shellscript mime-type: text/plain mime-type: text/plain mime-type: text/plain mime-type: text/plain mime-type: text/plain 

    Ваша проблема связана с расширением оболочки. $ () разворачивается до передачи в качестве аргумента. Если вы хотите рассматривать его как есть, оставьте его и назовите для него оболочкой.

    Кроме того, если вы обрабатываете имена файлов, привыкайте использовать print0 и 0, как их оставляете, это создаст проблемы для вас с именами файлов, содержащими пробельный символ.

    Пример:

     find . -type f -print0 | xargs -0 -n 1 -I FILE bash -c 'echo $(file --mime-type -b FILE)' 

    В вашем случае это может быть упрощено:

     find . -type f -print0 | xargs -0 -n 1 file --mime-type -b 

    Дополнительный комментарий: вызов программы для всех найденных файлов (будь то «xargs -n 1» или find + exec) может стать настоящим узким местом производительности. Если у вас есть каталог с тысячами файлов, вы создадите тысячи процессов.

    Linux и Unix - лучшая ОС в мире.