list=`ls -a R*`
echo $list
Внутри сценария оболочки эта команда echo выведет список всех файлов из текущего каталога, начиная с R, но в одной строке. Как я могу напечатать каждый элемент в одной строке?
Мне нужна общая команда для всех сценариев происходят с ls
, du
, find -type -d
и т.д.
Ответы:
Если выходные данные команды содержат несколько строк, заключите в кавычки ваши переменные, чтобы сохранить эти символы новой строки при выводе:
В противном случае оболочка развернет и разделит содержимое переменных на пробелы (пробелы, новые строки, табуляции), и они будут потеряны.
источник
Вместо того, чтобы опрометчиво помещать
ls
выходные данные в переменную, а затем использоватьecho
ее, которая удаляет все цвета, используйтеОт
man ls
Я не советую вам делать что-либо с выводом
ls
, кроме отображения :)Используйте, например, оболочки оболочки и
for
цикл, чтобы сделать что-то с файлами ...* это не будет включать текущий каталог
.
или его родителя,..
хотяисточник
echo "$i"
наprintf "%s\n" "$i"
(это не захлебнется, если имя файла начинается с "-"). На самом деле, большую часть времениecho something
следует заменить наprintf "%s\n" "something"
.R
здесь, но в целом да. Тем не менее, даже для сценариев попытка всегда учитывать ведущий-
в путях вызывает проблемы: люди предполагают--
, что только некоторые команды поддерживают, что означает конец опций. Я видел,find . [tests] -exec [cmd] -- {} \;
где[cmd]
не поддерживает--
. Каждый путь там начинается с в.
любом случае! Но это не аргумент против заменыecho
наprintf '%s\n'
. Здесь можно заменить весь цикл наprintf '%s\n' R/*
. Bash имеетprintf
встроенную функцию, поэтому количество аргументов не ограничено.В то время как положить его в кавычки , как @muru предложил действительно делать то , что вы просили, вы можете также рассмотреть возможность использования массива для этого. Например:
Команда
IFS=$'\n'
bash сообщает только о том, что нужно разделить вывод на символы новой строки, чтобы получить каждый элемент массива. Без этого он будет разделен на пробелы, поэтомуa file name with spaces.txt
было бы 5 отдельных элементов вместо одного. Этот подход сломается, если ваши имена файлов / каталогов могут содержать newlines (\n
). Это сохранит каждую строку вывода команды как элемент массива.Обратите внимание , что я также изменил старый стиль
`command`
в$(command)
котором предпочтительный синтаксис.Теперь у вас есть массив с именем
$dirs
bof, каждый элемент которого является строкой вывода предыдущей команды. Например:Теперь, из-за некоторой странности bash (см. Здесь ), вам нужно будет
IFS
вернуться к исходному значению после этого. Итак, либо сохраните его и переназначьте:Или сделайте это вручную:
Или просто закройте текущий терминал. Ваш новый будет иметь оригинальный набор IFS снова.
источник
du
это выглядит, OP больше заинтересована в сохранении выходного формата.Если вам нужно сохранить выходные данные и вы хотите массив,
mapfile
это легко.Во-первых, подумайте, нужно ли вообще сохранять выходные данные вашей команды. Если нет, просто запустите команду.
Если вы решите, что хотите прочитать вывод команды в виде массива строк, это правда, что один из способов сделать это - отключить глобализацию, установить
IFS
разбиение на строки, использовать подстановку команд в(
)
синтаксисе создания массива и выполнить сбросIFS
после этого, что сложнее, чем кажется. Ответ Тердона охватывает некоторые из этого подхода. Но я предлагаю вам использовать встроенную командуmapfile
оболочки Bash для чтения текста в виде массива строк. Вот простой случай, когда вы читаете из файла:Это читает строки в массив с именем
MAPFILE
. Без перенаправления ввода вы будете читать из стандартного ввода оболочки (обычно вашего терминала) вместо файла с именем . Для чтения в массив, отличный от значения по умолчанию , передайте его имя. Например, это читает в массив :< filename
filename
MAPFILE
lines
Другое поведение по умолчанию, которое вы можете изменить, состоит в том, что символы новой строки в концах строк остаются на месте; они появляются как последний символ в каждом элементе массива (если только ввод не завершился без символа новой строки, в этом случае последний элемент не имеет такового). Чтобы сжать эти новые строки, чтобы они не появлялись в массиве, передайте
-t
опциюmapfile
. Например, это читает в массивrecords
и не записывает завершающие символы новой строки в его элементы массива:Вы также можете использовать
-t
без передачи имени массива; то есть он также работает с неявным именем массиваMAPFILE
.mapfile
Оболочки встроенной опоры и другие варианты, и он в качестве альтернативы может быть вызван в качествеreadarray
. Запуститеhelp mapfile
(иhelp readarray
) для деталей.Но вы не хотите читать из файла, вы хотите читать из вывода команды. Чтобы добиться этого, используйте процесс подстановки . Эта команда читает строки из команды
some-command
сarguments...
аргументами командной строки и помещает их вmapfile
массив по умолчаниюMAPFILE
с удаленными завершающими символами новой строки:Подстановка процесса заменяется реальным именем файла, из которого можно прочитать результаты выполнения. Файл является именованным каналом, а не обычным файлом, и в Ubuntu он будет именоваться как (иногда с другим номером, чем ), но вам не нужно заботиться о деталях, потому что оболочка заботится об этом все за кадром.
<(some-command arguments...)
some-command arguments...
/dev/fd/63
63
Вы можете подумать, что можете отказаться от замены процесса, используя вместо этого, но это не сработает, потому что, когда у вас есть конвейер из нескольких команд, разделенных Bash, запускает все команды в подоболочках . Таким образом оба и запускаются в своих собственных средах , инициализируемых, но отдельно от среды оболочки, в которой вы запускаете конвейер. В субоболочке , где работает, то массив имеет получить населенную, но затем этот массив отбрасываются , когда концы команд. никогда не создается и не изменяется для вызывающей стороны.
some-command arguments... | mapfile -t
|
some-command arguments...
mapfile -t
mapfile -t
MAPFILE
MAPFILE
Вот как выглядит пример в ответе Тердона , если вы используете
mapfile
:Вот и все. Вам не нужно проверять,
IFS
был ли он установлен , отслеживать, было ли оно установлено и с каким значением, устанавливать его на новую строку, а затем сбрасывать или сбрасывать его позже. Вам не нужно отключить подстановку (например, сset -f
) , - которые действительно необходимы , если вы хотите использовать этот метод серьезно, так как имена файлов могут содержать*
,?
и[
--then повторно включить его (set +f
) впоследствии.Вы также можете полностью заменить этот конкретный цикл одной
printf
командой - хотя это на самом деле не является преимуществомmapfile
, так как вы можете сделать это независимо от того, используете ли выmapfile
или другой метод для заполнения массива. Вот более короткая версия:Важно помнить, что, как упоминает Тердон , построчная работа не всегда уместна и не будет корректно работать с именами файлов, которые содержат переводы строк. Я рекомендую не называть файлы таким образом, но это может произойти, в том числе и случайно.
На самом деле не существует универсального решения.
Вы просили «общую команду для всех сценариев» и подход, основанный на использовании
mapfile
нескольких подходов к этой цели, но я призываю вас пересмотреть ваши требования.Задача, показанная выше, лучше достигается с помощью одной
find
команды:Вы также можете использовать внешнюю команду, например,
sed
добавитьDIR:
в начало каждой строки. Это, возможно, несколько уродливо, и в отличие от этой команды find, она добавит дополнительные «префиксы» в имена файлов, содержащие символы новой строки, но она работает независимо от ее ввода, поэтому она как бы соответствует вашим требованиям и все же предпочтительнее считывать вывод в переменная или массив :Если вам нужно перечислить, а также выполнить действие для каждого найденного каталога, например, запустить
some-command
и передать путь к каталогу в качестве аргумента, тоfind
вы тоже можете это сделать:В качестве другого примера, давайте вернемся к общей задаче добавления префикса к каждой строке. Предположим, я хочу увидеть результат,
help mapfile
но нумеровать строки. Я бы на самом деле не использовалmapfile
для этого ни какой-либо другой метод, который считывает его в переменную оболочки или массив оболочки. Предположимhelp mapfile | cat -n
, не дает нужного мне форматирования, я могу использоватьawk
:Чтение всех выходных данных команды в одну переменную или массив иногда полезно и целесообразно, но имеет серьезные недостатки. Вам не только приходится сталкиваться с дополнительной сложностью использования вашей оболочки, когда существующая команда или комбинация существующих команд может уже делать то, что вам нужно, либо лучше, но весь вывод команды должен храниться в памяти. Иногда вы можете знать, что это не проблема, но иногда вы можете обрабатывать большой файл.
Альтернатива, которую обычно пытаются (а иногда и делают правильно), - читать входные данные построчно
read -r
в цикле. Если вам не нужно сохранять предыдущие строки при работе с более поздними строками, и вам нужно использовать длинный ввод, тогда это может быть лучше, чемmapfile
. Но этого также следует избегать в тех случаях, когда вы можете просто передать его команде, которая может выполнить эту работу, что и происходит в большинстве случаев .источник