list=`ls -a R*`
echo $list
В сценарии оболочки эта команда эха перечислит все файлы из текущего каталога, запускающегося с R, но в одной строке. Как я могу распечатать каждый объект на одной строке?
Мне нужна групповая команда для всех сценариев, происходящих с ls
, du
, find -type -d
, и т.д.
Если вывод команды содержит несколько строк, то заключите свои переменные в кавычки для сохранения тех новых строк при повторении:
echo "$list"
Иначе оболочка развернет и разделит переменное содержание на пробеле (пробелы, новые строки, вкладки), и они будут потеряны.
Вместо опрометчивого помещения ls
вывод в переменной и затем echo
луг это, который удаляет все цвета, использует
ls -a1
От man ls
-1 list one file per line. Avoid '\n' with -q or -b
Я не советую сделать что-либо с выводом ls
, кроме дисплея это :)
Используйте, например, шарики оболочки и a for
цикл, чтобы сделать что-то с файлами...
shopt -s dotglob # to include hidden files*
for i in R/*; do echo "$i"; done
* это не будет включать текущий каталог .
или его родитель ..
хотя
В то время как помещение его в кавычках как @muru предложенный действительно сделает то, что Вы попросили, Вы могли бы также хотеть рассмотреть использование массива для этого. Например:
IFS=$'\n' dirs=( $(find . -type d) )
IFS=$'\n'
говорит, что удар, чтобы только разделить вывод на символах новой строки o получает каждый элемент массива. Без него он разделит на пробелах, таким образом, a file name with spaces.txt
были бы 5 отдельных элементов вместо одного. Этот подход повредится, если Ваш файл/имена каталогов может содержать новые строки (\n
)все же. Это сохранит каждую строку вывода команды как элемент массива.
Обратите внимание, что я также изменил старого стиля `command`
кому: $(command)
который является предпочтительным синтаксисом.
Вам теперь назвали массив $dirs
, каждый bof, элементы которого являются строкой вывода предыдущей команды. Например:
$ find . -type d
.
./olad
./ho
./ha
./ads
./bar
./ga
./da
$ IFS=$'\n' dirs=( $(find . -type d) )
$ for d in "${dirs[@]}"; do
echo "DIR: $d"
done
DIR: .
DIR: ./olad
DIR: ./ho
DIR: ./ha
DIR: ./ads
DIR: ./bar
DIR: ./ga
DIR: ./da
Теперь, из-за некоторой странности удара (см. здесь), необходимо будет сбросить IFS
назад к исходному значению после выполнения этого. Так, любое сохранение это и reasign:
oldIFS="$IFS"
IFS=$'\n' dirs=( $(find . -type d) )
IFS="$oldIFS"
Или сделайте это вручную:
IFS=" "$'\t\n '
С другой стороны, просто закройте текущий терминал. Вашему новому установят исходную IFS снова.
mapfile
помогает.Во-первых, рассмотрите, необходимо ли сохранить вывод команды вообще. Если Вы не делаете, просто выполняете команду.
Если Вы решаете, что хотите считать вывод команды как массив строк, это верно, что один способ сделать это состоит в том, чтобы отключить globbing, установить IFS
для разделения на строках используйте замену команды в (
)
синтаксис создания массива и сброс IFS
впоследствии, который более сложен, чем это кажется. ответ terdon касается части того подхода. Но я предлагаю, чтобы Вы использовали mapfile
, встроенная команда оболочки Bash для чтения текста как массив строк, вместо этого. Вот простой случай, где Вы читаете из файла:
mapfile < filename
Это читает строки в названный массив MAPFILE
. Без перенаправления ввода < filename
, Вы читали бы из стандартного входа оболочки (обычно Ваш терминал) вместо файла, названного filename
. Читать в массив кроме значения по умолчанию MAPFILE
, передайте его имя. Например, это читает в массив lines
:
mapfile lines < filename
Другое поведение по умолчанию, которое Вы могли бы принять решение изменить, состоит в том, что символы новой строки в концах строк оставляют на месте; они появляются как последний знак в каждом элементе массива (если вход, законченный без символа новой строки, в этом случае последний элемент, не имеет одного). Для чавкания этих новых строк, таким образом, они не появляются в массиве передайте -t
опция к mapfile
. Например, это читает в массив records
и не пишет запаздывание символов новой строки в его элементы массива:
mapfile -t records < filename
Можно также использовать -t
не передавая имя массива; то есть, это работает с неявным названием массива MAPFILE
, также.
mapfile
окружите встроенные поддержки другие опции, и это может альтернативно быть вызвано как readarray
. Выполненный help mapfile
(и help readarray
) для деталей.
Но Вы не хотите читать из файла, Вы хотите читать из вывода команды. Для достижения этого используйте замену процесса. Эта команда читает строки из команды some-command
с arguments...
как его параметры командной строки и места в них в mapfile
массив по умолчанию MAPFILE
, с их удаленными символами новой строки завершения:
mapfile -t < <(some-command arguments...)
Замены замены процесса <(some-command arguments...)
с фактическим именем файла, от который вывод выполнения some-command arguments...
может быть считан. Файл является именованным каналом, а не регулярным файлом и на Ubuntu, как это назовут /dev/fd/63
(иногда с некоторым другим числом, чем 63
), но Вы не должны интересоваться деталями, потому что оболочка заботится обо всем этом негласно.
Вы могли бы думать, что могли воздержаться от замены процесса при помощи some-command arguments... | mapfile -t
вместо этого, но это не будет работать, потому что, когда у Вас будет конвейер нескольких команд, разделенных |
, Выполнения Bash выполняют все команды в подоболочках. Таким образом оба some-command arguments...
и mapfile -t
выполненный в их собственных средах, инициализированных от, но отдельный от среды оболочки, в которой Вы выполняете конвейер. В подоболочке, где mapfile -t
выполнения, MAPFILE
массив действительно становится заполненным, но затем что массив отбрасывается, когда команда заканчивается. MAPFILE
никогда не создается или изменяется для вызывающей стороны.
Вот то, на что пример в ответе terdon похож, полностью, если Вы используете mapfile
:
mapfile -t dirs < <(find . -type d)
for d in "${dirs[@]}"; do
echo "DIR: $d"
done
Именно. Вы не должны проверять если IFS
был установлен, отслеживайте то, было ли не это установлено и с тем, какое значение, установило его на новую строку, затем сброс или повторно сбросило его позже. Вы не должны отключать globbing (например, с set -f
) - который действительно необходим, если необходимо использовать тот метод серьезно, начиная с, имена файлов могут содержать *
, ?
, и [
- затем повторно включите его (set +f
) впоследствии.
Можно также заменить тот конкретный цикл полностью синглом printf
команда - хотя это не на самом деле преимущество mapfile
, поскольку можно сделать это, используете ли Вы mapfile
или другой метод для заполнения массива. Вот более короткая версия:
mapfile -t < <(find . -type d)
printf 'DIR: %s\n' "${MAPFILE[@]}"
Важно иметь в виду, что, как terdon упоминания, работая линию за линией является не всегда соответствующим, и не будет работать правильно с именами файлов, которые содержат новые строки. Я рекомендую против именования файлов тот путь, но это может произойти, включая случайно.
Вы попросили "групповую команду для всех сценариев" и подход использования mapfile
несколько подходы, что цель, но я убеждаю Вас пересмотреть свои требования.
Задача, показанная выше, лучше достигается только с синглом find
команда:
find . -type d -printf 'DIR: %p\n'
Вы могли также использовать внешнюю команду как sed
добавить DIR:
к началу каждой строки. Это возможно несколько ужасно, и в отличие от той находки управляют, чтобы она добавила дополнительные "префиксы" в именах файлов, которые содержат новые строки, но она действительно работает независимо от своего входа так это, вид отвечает Вашим требованиям, и это все еще предпочтительно для чтения вывода в переменную или массив:
find . -type d | sed 's/^/DIR: /'
Если необходимо перечислить и также выполнить действие с каждым найденным каталогом, таким как выполнение some-command
и передача пути каталога как аргумент, find
позволяет Вам сделать это также:
find . -type d -print -exec some-command {} \;
Как другой пример, давайте возвратимся к общей задаче добавления префикса к каждой строке. Предположим, что я хочу видеть вывод help mapfile
но пронумеруйте строки. Я на самом деле не использовал бы mapfile
для этого, ни любого другого метода, который читает его в переменную оболочки или массив оболочки. Предположим, help mapfile | cat -n
не дает форматирование, которое я хочу, я могу использовать awk
:
help mapfile | awk '{ printf "%3d: %s\n", NR, $0 }'
Чтение всего вывода команды в к единственной переменной или массиву является иногда полезным и соответствующим, но это имеет главные недостатки. Мало того, что необходимо иметь дело с дополнительной сложностью использования оболочки, когда существующая команда или комбинация существующих команд могут уже сделать то, в чем Вы нуждаетесь также или лучше, но весь вывод команды должен быть сохранен в памяти. Иногда можно знать, что это не проблема, но иногда можно обрабатывать большой файл.
Альтернатива, которая обычно предпринимается - и иногда делается правильно - должна считать вход линию за линией с read -r
в цикле. Если Вы не должны хранить предыдущие строки при работе на более поздние строки, и необходимо использовать долго вход, то это может быть лучше, чем mapfile
. Но также нужно избежать в случаях, когда можно просто передать его по каналу к команде, которая может сделать работу, которая является большинством случаев.