Заставьте xargs обрабатывать имена файлов, содержащие пробелы

$ ls *mp3 | xargs mplayer  

Playing Lemon.  
File not found: 'Lemon'  
Playing Tree.mp3.  
File not found: 'Tree.mp3'  

Exiting... (End of file)  

Моя команда не работает, потому что файл "Lemon Tree.mp3 " содержит пробелы и поэтому XARGS думает, что этос двумя файлами. Можно ли заставить find + xargs работать с такими именами файлов?

 imz -- Ivan Zakharyaschev11 мая 2017 г., 14:24
 Micha Wiedenmann26 мая 2013 г., 12:58
Вместоls |grep mp3 |sed -n "7p" Вы можете просто использовать.echo "Lemon Tree.mp3"
 imz -- Ivan Zakharyaschev11 мая 2017 г., 14:25
На этот вопрос также отвечаетstackoverflow.com/a/33528111/94687

Ответы на вопрос(12)

Пытаться

find . -name \*.mp3 -print0 | xargs -0 mplayer

вместо

ls | grep mp3 
Решение Вопроса

xargs Команда принимает символы пробела (табуляции, пробелы, новые строки) в качестве разделителей. Вы можете сузить его только для символов новой строки ('') с-d вариант как этот:

Работает только с GNU xargs. Для систем BSD используйте-0 вариант как этот:

ls *.mp3 | xargs -0 mplayer

Этот метод проще и работает с GNU xargs.

 tofutim25 мар. 2018 г., 23:37
gxargs для победы
 Ray14 мар. 2019 г., 11:10
Можете ли вы подтвердить, работает ли второй метод на OSX или нет, пожалуйста? Благодарю.
 Thomas Tempelmann14 нояб. 2016 г., 16:42
К сожалению, эта опция недоступна в OS X.
 user206295018 янв. 2017 г., 19:09
@Thomas Для OS X флаг-EПример:xargs -E '\n'
 biomiker05 июл. 2017 г., 09:23
На OS X, -E '\ П» А не было»Это не повлияет на меня, и я не ожидаю, что это изменит eofstr, а не разделитель записей. Тем не менее, я смог использовать флаг -0 в качестве решения, даже если предыдущая команда не была 'находить', имитируя эффект поискаs -print0 флаг на моем входе, например: ls * mp3 | тр\ П» '\ 0' | xargs -0 mplayer
 nexayq18 июн. 2016 г., 19:02
Лучший ответ для общего пользования! Это работает, даже если ваша предыдущая команда не "находить"
 Tom De Leu16 мар. 2018 г., 10:37
Для OS X вы можетеBrew Install Findutils ", который дает вам "gxargs» командовать этимделает есть ключ -d.

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g'

Идея состоит в том, чтобы преобразовать пробелы в любой уникальный символ, например '<'и затем измените это на '\'обратная косая черта с последующим пробелом. Затем вы можете передать это в любую команду, которая вам нравится, например:

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g' | xargs -L1 GetFileInfo

Ключ здесь лежит втр» а также 'СЭД» команды; и вы можете использовать любой символ, кроме «<», такие как '?' или даже символ табуляции.

 tripleee04 февр. 2016 г., 17:58
Какие'с целью обходаtr? Почему не просто? Яls *.mp3 | sed -n '7!b;s/\([[:space:]]\)/\\\1/g;p'
 Dick Guertin05 февр. 2016 г., 16:50
мы обнаружили, что "тр ' "?» устраняет необходимостьСЕПГ», Сингл "?" символ не является пустым, но соответствует ЛЮБОМУ одиночному символу, в этом случае: пустой. Вероятность того, что это что-то другое, довольно мала и приемлема, так как выпытается обработать ВСЕ файлы, заканчивающиеся на .mp3: "ls | grep ' ' | тр ' '?' | xargs -L1 GetFileInfo "
 Dick Guertin05 февр. 2016 г., 17:02
Вы также можете справитьсявкладка» в то же время: tr ' \ Т» '??» обрабатывает оба.
find . -name 'Lemon*.mp3' -print0 | xargs -­0 -i mplayer '{}' 

работать тоже с mplayer. Необходимый трюк - это цитаты. (Проверено на LinuxXubuntu 14,04.)

ls | grep mp3 | sed -n "7p" | xargs -i mplayer {}

Обратите внимание, что в приведенной выше командеxargs позвонюmplayer заново для каждого файла. Это может быть нежелательно дляmplayer, но может быть хорошо для других целей.

 user74338225 авг. 2014 г., 19:25
Полезное дополнение к существующим ответам, но стоит отметить, что это вызоветmplayer называться заново для каждого файла. Это важно, если вы попробуете, например,... | xargs -I{} mplayer -shuffle {}: это будет играть в полностью детерминированном порядке, несмотря на.-shuffle
 user74338225 авг. 2014 г., 21:40
Это'Скорее всего, обычно не намерение.xargs в основном используется с командами, которые принимают список имен файлов (простой пример:rm) и пытается передать столько имен файлов, сколько оно может уместиться в каждом вызове, разделяя только на несколько вызовов, если это необходимо. Вы можете увидеть разницу, когда используете команду, в которой виден каждый вызов, напримерecho (по умолчанию):seq 0 100000 | xargs печатает все числа от 0 до 23695 (зависит от платформы, но эточто происходит в моей системе) в первой строке, до 45539 в строке 2 и т. д.верно, для большинства команд, он выигралне имеет значения.

Ответ s [1] предположил, что можно избежать пробелов в имени файла, является ценной альтернативой другим решениям, предложенным здесь (таким как использование нулевого символа в качестве разделителя, а не пробела). Но это может быть проще - ты неТ действительно нужен уникальный персонаж. Вы можете просто с помощью sed добавить экранированные пробелы напрямую:

ls | grep ' ' | sed 's| |\\ |g' | xargs ...

Кроме того, grep необходим только если вытолько хочу файлы с пробелами в именах. В более общем смысле (например, при обработке пакета файлов, некоторые из которых имеют пробелы, а некоторые нет), просто пропустите grep:

ls | sed 's| |\\ |g' | xargs ...

Тогда, конечно, имя файла может иметь другие пробелы, кроме пробелов (например, вкладка):

ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...

Это предполагает, что у вас есть sed, который поддерживает -r (расширенное регулярное выражение), такой как GNU sed или последние версии bsd sed (например, FreeBSD, в которой изначально была указана опция "-E» до FreeBSD 8 и поддерживает как -r & -E для совместимости через FreeBSD 11 как минимум). В противном случае вы можете использовать скобочное выражение для базового класса регулярных выражений и вручную ввести символы пробела и табуляции в[] разделители.

[1] Возможно, это более уместно в качестве комментария или редактирования этого ответа, но на данный момент у меня недостаточно репутации, чтобы комментировать, и я могу только предлагать правки. Поскольку последние формы выше (без grep) изменяют поведение Дика. ГертингаС оригинальным ответом, прямое редактирование, возможно, не подходит в любом случае.

 glyph29 дек. 2016 г., 01:01
Имя файла с вкладкой в нем! Кто делает такие вещи ???
 andrew lorien11 апр. 2017 г., 10:40
сумасшедшие парни из Unix, которые запускают сценарии с именами файлов, не учитывая их вывод,с кем

Я знаю, что яя не отвечаю наxargs вопрос напрямую но это'Стоит упомянутьfind-exec вариант.

Учитывая следующую файловую систему:

[[email protected] bokeh]# tree --charset assci bands
bands
|-- Dream\ Theater
|-- King's\ X
|-- Megadeth
`-- Rush

0 directories, 4 files

Команда find может быть использована для обработки пространства в Dream Theater и King 's X. Итак, чтобы найти барабанщиков каждой группы, используя grep:

[[email protected]]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren

в-exec вариант{} обозначает имя файла, включая путь. Обратите внимание, что вы нене нужно избегать этого или ставить его в кавычки.

Разница между '-execтерминаторы (+ а также\;) в том, что+ группирует как можно больше имен файлов в одну командную строку. В то время как\; выполнит команду для каждого имени файла.

Так,find bands/ -type f -exec grep Drums {} + приведет к:

grep Drums "bands/Dream Theater" "bands/Rush" "bands/King's X" "bands/Megadeth"

а такжеfind bands/ -type f -exec grep Drums {} \; приведет к:

grep Drums "bands/Dream Theater"
grep Drums "bands/Rush"
grep Drums "bands/King's X"
grep Drums "bands/Megadeth"

В случаеgrep это имеет побочный эффект печати имени файла или нет.

[[email protected] bokeh]# find bands/ -type f -exec grep Drums {} \;
Drums:Mike Mangini
Drums: Neil Peart
Drums:Jerry Gaskill
Drums:Dirk Verbeuren

[[email protected] bokeh]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren

Конечно, 'grepварианты-h а также-H будет контролировать, будет ли печататься имя файла независимо от того, какgrep называется.

xargs

xargs также может контролировать, как файлы man находятся в командной строке.

xargs по умолчанию группирует все аргументы в одну строку. Для того, чтобы сделать то же самое, что-exec \; действительно используетxargs -l, Обратите внимание, что-t вариант говоритxargs распечатать команду перед ее выполнением.

[[email protected] bokeh]# find ./bands -type f  | xargs -d '\n' -l -t grep Drums
grep Drums ./bands/Dream Theater 
Drums:Mike Mangini
grep Drums ./bands/Rush 
Drums: Neil Peart
grep Drums ./bands/King's X 
Drums:Jerry Gaskill
grep Drums ./bands/Megadeth 
Drums:Dirk Verbeuren

Видите, что-l опция указывает xargs выполнять grep для каждого имени файла.

По сравнению со значением по умолчанию (т.е. нет-l опция):

[[email protected] bokeh]# find ./bands -type f  | xargs -d '\n'  -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush ./bands/King's X ./bands/Megadeth 
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren

xargs имеет лучший контроль над тем, сколько файлов может быть в командной строке. Дай-l Опция максимальное количество файлов на команду.

[[email protected] bokeh]# find ./bands -type f  | xargs -d '\n'  -l2 -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush 
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
grep Drums ./bands/King's X ./bands/Megadeth 
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren
[[email protected] bokeh]# 

Видеть, чтоgrep был выполнен с двумя именами файлов из-за.-l2

поэтому в этом решении вместо нее используется -0.

Получите ls для вывода по одному файлу на строку, затем переведите новые строки в null и скажите xargs использовать null в качестве разделителя:

ls -1 *mp3 | tr "\n" "\0" | xargs -0 mplayer

в отличие, скажем, от Лимонов, и (б) от того, содержат ли какие-либо имена файлов новые строки (и от того,готовы переименовать их, если они это сделают).

Есть много способов справиться с этим, но некоторые из них:

mplayer Lemon*.mp3

find . -name 'Lemon*.mp3' -exec mplayer {} ';'

i=0
for mp3 in *.mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

for mp3 in *.mp3
do
    case "$mp3" in
    (Lemon*) mplayer "$mp3";;
    esac
done

i=0
find . -name *.mp3 |
while read mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

read петля не делаетt работает, если имена файлов содержат символы новой строки; остальные работают правильно даже с символами новой строки в именах (не говоря уже о пробелах). За мои деньги, если у вас есть имена файлов, содержащие новую строку, вы должны переименовать файл без новой строки. Использование двойных кавычек вокруг имени файла является ключом к правильной работе циклов.

Если у вас есть GNUfind и GNUxargs (или FreeBSD (* BSD?), или Mac OS X), вы также можете использовать-print0 а также-0 варианты, как в:

find . -name 'Lemon*.mp3' -print0 | xargs -0 mplayer

Это работает независимо от содержимого имени (только два символа, которые не могут отображаться в имени файла, - это косая черта и NUL, и косая черта не вызывает проблем в пути к файлу, поэтому использование NUL в качестве разделителя имен охватывает все). Однако, если вам нужно отфильтровать первые 6 записей, вам нужна программа, которая обрабатываетлинии закончился NUL вместо новой строки ... и яЯ не уверен, что есть.

Первый, безусловно, самый простой для конкретного случая под рукой; тем не менее, он может не распространяться на другие ваши сценарии, которые вымы еще не перечислены.

символами табуляции, новой строки и конца файла и выполняет утилиту со строками в качестве аргументов.

Вы хотите избежать использования пробела в качестве разделителя. Это можно сделать, изменив разделитель для xargs. Согласно инструкции:

 -0      Change xargs to expect NUL (``\0'') characters as separators,
         instead of spaces and newlines.  This is expected to be used in
         concert with the -print0 function in find(1).

Такие как:

 find . -name "*.mp3" -print0 | xargs -0 mplayer

Ответить на вопрос о проигрывании седьмого mp3; проще бежать

 mplayer "$(ls *.mp3 | sed -n 7p)"
 Ahmed Fasih27 мая 2015 г., 15:10
@YordanGeorgiev ваш комментарий (особенно с @joensson 'с использованиемtr вместо perl) должен быть ответ!
 Jonathan Leffler26 мая 2013 г., 13:24
Это использует GNUfind и GNUxargs; не все версии этих программ поддерживают эти опции (хотяэто должно быть сделано, что они должны).
 user280721901 мая 2017 г., 18:06
@JonathanLeffler, спасибо за ответ, я попробовал еще раз, проблема не в пробелах, поиск с помощью xargs работает с пробелами даже без -print0 и -0. Моя настоящая проблема в том, что имена папок и файлов слишком длинные, тогда результат выполнения будет "mv: переименовать {} в / pathTo / {}: нет такого файла или каталога ".
 Jens26 мая 2013 г., 13:30
@JonathanLeffler s / GNU / FreeBSD / g; POSIX, к сожалению, боится NUL символов в текстовых файлах и неТерапии было достаточно :-) На самом деле мой совет прибегает к непереносимым вариантам.
 joensson01 нояб. 2014 г., 09:24
Хорошая идея заменить символы новой строки на NUL - я должен был сделать это во встроенной системе, в которой не было ни GNU-поиска, ни GNU-xargs, ни perl-но команда tr может быть использована для того же: cat $ file_paths_list_file | тр\ П» '\ 0' | xargs -0 du -hms
 user280721929 апр. 2017 г., 12:35
@JonathanLeffler, хотя в macos есть -print0 и -0, он не работает, если имя файла содержит пробел.
 Jonathan Leffler26 мая 2013 г., 13:45
И Mac OS X (производная от BSD) имеетfind с-print0 а такжеxargs с-0, AFAIK, HP-UX, AIX и Solaris, однако, нет (но я должен исправить: HP-UX 11i не сделалт; Солярис 10 не сделалт; AIX 5.x не сделалт; но они'не текущие версии). Это неэто трудно изменитьsedнапример, использоватьлинии заканчивая'\0' вместо'\n'и POSIX 2008getdelim() облегчит управление
 Jonathan Leffler30 апр. 2017 г., 13:34
@ user2807219: яМне интересно узнать, как вы это демонстрируете. Меня устраивает. Если нужно, отправьте мне письмо - Смотри мой профиль - и включите ссылку на этот вопрос и MCVE, который демонстрирует, как вы сталкиваетесь с проблемами.
 Yordan Georgiev24 июн. 2014 г., 15:47
+1 + 1 трюк для использования с путями к файлам, содержащим файлы списка: cat $ file_paths_list_file | perl -ne 's | \ п | \ 000 | г, печать»| xargs -0 zip $ zip_package
 Jonathan Leffler01 мая 2017 г., 21:24
@ user2807219: Этос любопытно Это'также совершенно разные. У меня однажды была проблема с тестом конфигурации программного обеспечения, который не удался на очень, очень глубокой иерархии каталогов на Mac - он пытался проверить, насколько глубоко они могли зайти и запутался, чему способствовала ошибка Mac OS X. Но это было бы необычно. Или создайте свой собственный вопрос с изложением проблемы или свяжитесь со мной в автономном режиме с деталями. Вероятно, есть способы справиться с этим, но выВам нужно будет узнать и объяснить, почему у вас такие длинные имена, проиллюстрировать несколько примеров (они выиграливписаться в комментарий), и объяснить, что выпытаюсь сделать.

если у вас есть пробелы в именах файлов или подкаталогах, вы можете использовать следующее:

find . -name '*.swift' -exec echo '"{}"' \; |xargs wc -l

Вы также можете добавить нулевой символ в конец ваших строк, используя Perl, а затем использовать-0 вариант в xargs. В отличие от xargs -d '' (в утвержденном ответе) - это работает везде, включая ОСИКС.

Например, для рекурсивного перечисления (выполнения, перемещения и т. Д.) Изображений JPEG, которые могут содержать пробелы или другие забавные символы - ябуду использовать:

find . | grep \.jpg | perl -ne 'chop; print "$_\0"' | xargs -0  ls

(Примечание: для фильтрации я предпочитаю «легче запомнить»| Grep» синтаксис "найти в» - имя аргумента.)

Ваш ответ на вопрос