Я хочу передать имена файлов другим программам, но все они задыхаются, когда имена содержат пробелы.
Допустим, у меня есть файл с именем.
foo bar
Как я могу find
вернуть правильное имя?
Очевидно, я хочу:
foo\ bar
или:
"foo bar"
РЕДАКТИРОВАТЬ : Я не хочу проходить xargs
, я хочу получить правильно отформатированную строку, find
чтобы я мог передать строку имен файлов непосредственно в другую программу.
-exec
флаге сfind
? Вы могли бы потенциально устранить эту ошибку и сделать свою команду более эффективной, выполнив-exec
вместо передачи ее другим командам. Просто мои $ .02find
форматирует имена файлов просто отлично; они написаны по одному имени в строке. (Конечно, это неоднозначно, если имя файла содержит символ новой строки.) Таким образом, проблема заключается в том, что принимающая сторона «задыхается», когда получает пробел, а это означает, что вы должны сказать нам, что является получающей стороной, если вы хотите значимого ответа ,find
предложить вариант вывода имен файлов в формате, подходящем для оболочки. В целом, однако, расширение-print0
GNUfind
прекрасно работает для многих других сценариев (тоже), и вы должны научиться использовать его в любом случае.ls $(command...)
не прокручивает списокstdin
. Он помещает вывод$(command...)
непосредственно в командную строку. В этом случае это оболочка, которая читает из c, и она будет использовать текущее значение,$IFS
чтобы решить, как разбить вывод на слово. В общем, вам лучше использоватьxargs
. Вы не заметите удар по производительности.find -printf '"%p"\n'
добавит двойные кавычки вокруг каждого найденного имени, но не будет правильно заключать в кавычки двойные кавычки в имени файла. Если в именах ваших файлов нет встроенных двойных кавычек, вы можете проигнорировать проблему: или передать черезsed 's/"/&&/g;s/^""/"/;s/""$/"/'
. Если ваши имена файлов в конечном итоге обрабатываются оболочкой, вы, вероятно, должны использовать одинарные кавычки вместо двойных кавычек (в противном случаеsweet$HOME
это станет чем-то вродеsheet/home/you
). И это все еще не очень устойчиво к именам файлов с символами новой строки в них. Как вы хотите справиться с этим?Ответы:
POSIXLY:
С
find
опорами-print0
иxargs
опорами-0
:-0
option указывает xargs использовать символ ASCII NUL вместо пробела для окончания (разделения) имен файлов.Пример:
источник
ls $(find . -maxdepth 1 -type f -print0 | xargs -0)
я получаюls: cannot access ./foo: No such file or directory
ls: cannot access bar: No such file or directory
$(..)
"$(..)"
find
иxargs
.С помощью
-print0
- это один из вариантов, но не все программы поддерживают использование потоков данных, разделенных нулем, поэтому вам придется использоватьxargs
этот-0
параметр для некоторых вещей, как отмечается в ответе Gnouc.Альтернативой было бы использовать
find
«с-exec
или-execdir
опций. Первое из следующего будет кормить имена файловsomecommand
одному за раз, а второе - в список файлов:Вы можете обнаружить, что во многих случаях вам лучше использовать шаровидность. Если у вас есть современная оболочка (bash 4+, zsh, ksh), вы можете получить рекурсивную глобализацию с помощью
globstar
(**
). В bash вы должны установить это:У меня есть строка с надписью
shopt -s globstar extglob
в моем .bashrc, поэтому она всегда включена для меня (как и расширенные глобусы, которые также полезны).Если вам не нужна рекурсивность, просто используйте
./*.txt
вместо нее каждый * .txt в рабочем каталоге.find
имеет некоторые очень полезные возможности детального поиска и является обязательным для десятков тысяч файлов (в этот момент вы столкнетесь с максимальным числом аргументов оболочки), но для повседневного использования это часто не требуется.источник
Лично я бы использовал действие
-exec
find для решения такого рода проблем. Или, если необходимо,xargs
что позволяет выполнять параллельное выполнение.Однако есть способ получить
find
список имен файлов, читаемый bash. Неудивительно, что он использует-exec
иbash
, в частности, расширениеprintf
команды:Однако, хотя это будет печатать правильно экранированные слова, оно не будет использоваться с
$(...)
, потому$(...)
что не интерпретирует кавычки или экранированные символы. (Результат зависит от$(...)
разбиения слов и расширения пути, если он не заключен в кавычки.) Таким образом, следующее не будет делать то, что вы хотите:Что вам нужно сделать, это:
(Обратите внимание, что я не предпринял никаких реальных попыток проверить вышеуказанное чудовище.)
Но тогда вы могли бы также сделать:
источник
ls
сценарий адекватно отражает сценарий использования ОП, но это всего лишь предположение, так как нам не было показано, чего он на самом деле пытается достичь. Это решение на самом деле работает очень хорошо; Я получаю вывод, который я (смутно) ожидал для всех забавных имен файлов, которые я пробовал, в том числеtouch "$(tr a-z '\001-\026' <<<'the quick brown fox jumped over the lazy dogs')"
eval
является то, что вам еще не нужно ее передаватьeval
; Вы можете сохранить его в параметре и использовать позже, возможно, несколько раз с разными командами. Однако OP не дает никаких указаний на то, что это тот случай использования (и если бы это было так, возможно, было бы лучше поместить имена файлов в массив, хотя это тоже сложно.)получит вам файлы и каталоги, содержащие пробелы
вы получите файлы с пробелами
вы получите каталоги, содержащие пробелы
источник
источник