нулевой символ очень особенный, и POSIX и bash не разрешают его внутри строк (это определение конца строки, поэтому $'\x00'
и $'\000'
почти никогда не работают; ответ Иниана здесь даже ссылается на обходной путь для ввода нулевого символа , но, опять же, вы не можете ожидать, что он будет должным образом сохранен, когда вы назначить его переменной). Похоже, что zsh не против, но bash.
Вот тест, который иллюстрирует проблемы, представляющие символы пробела, табуляции и новой строки в именах файлов:
$ touch 'two words' tabbed$'\t'words "two
lines"
$ ls # GNU coreutils ls displays using bash's $'string' notation
'tabbed'$'\t''words' 'two'$'\n''lines' 'two words'
$ ls |cat # … except when piped elsewhere
tabbed words
two
lines
two words
$ find * # GNU findutils find displays tabs & newlines as questions
tabbed?words
two?lines
two words
$ find * |cat # … except when piped elsewhere
tabbed words
two
lines
two words
$ touch a b c # (more tests for later)
Инструменты GNU очень умны и знают, что это проблема, поэтому они придумывают творческие пути, но они даже не последовательны. ls
предполагает, что вы используете bash или zsh (синтаксис $'…'
для литерала не присутствует в POSIX), а find
дает вам знак вопроса (сам по себе допустимый символ имени файла, но это глобус файла, который соответствует любому символу, например, rm two?lines tabbed?words
удалит оба файла, как rm 'two'$'\n''lines' 'tabbed'$'\t''words'
). Оба представляют правду, когда переданы другой команде, например cat
.
GNU / BSD / MacOSX / Busybox find и xargs
Я вижу, что вы используете расширения GNU: POSIX и BSD / OSX find
не допускают неявный путь, а POSIX find
не поддерживает -print0
, хотя POSIX find spec упоминает это:
Другие реализации добавили другие способы обойти эту проблему, в частности, -print0 , который записывал имена файлов с нулевым байтовым терминатором. Это было рассмотрено здесь, но не принято. Использование нулевого терминатора означало, что любая утилита, которая собиралась обработать вывод * -print0 , должна была добавить новую опцию для анализа нулевых терминаторов, которые она теперь будет читать.
Спецификация POSIX xargs также не поддерживает -0
(на нее также нет ссылок), хотя она поддерживается xargs
в GNU, BSD / OSX и busybox.
Следовательно, вы, вероятно, можете сделать это:
$ find . -type f -print0 |xargs -0
./c ./b ./a ./two
lines ./tabbed words ./two words
Однако вам может понадобиться массив, так что, возможно, я перебираю ваш упрощенный вопрос.
1058 * файл проект *
Вы можете использовать mapfile
в Bash 4.4 и более поздних версиях:
$ mapfile -d '' vars < <(find . -type f -print0)
$ printf '<%s>\n' "${vars[@]}"
<./c>
<./b>
<./a>
<./two
lines>
<./tabbed words>
<./two words>
Некоторые команды, включая mapfile
, read
и readarray
(синоним mapfile
), принимают -d ''
, как если бы это было -d $'\0'
, вероятно [требуется цитата] как обходной путь для вышеупомянутой неспособности оболочки POSIX работать с нулевыми символами в строках.
Эта команда mapfile
просто считывает входной файл (в данном случае стандартный ввод) в массив $vars
, разделенный нулевыми символами. Стандартный ввод заполняется через конвейер с помощью файлового дескриптора, созданного подстановкой процесса <(…)
в конце строки, который обрабатывает вывод нашей команды find
.
Небольшое отступление: вы могли бы подумать, что можете просто сделать find … |mapfile …
, но это изменит область, и все переменные, которые вы установили или изменили там, будут потеряны после завершения команды конвейера. Трюк с заменой процесса не подстерегает вас таким же образом.
Команда printf
просто демонстрирует содержимое массива. Угловые скобки обозначают начало и конец каждого элемента, поэтому вас не смущает перевод строки, пробел или табуляция.