У меня есть эта строка хранится в переменной:
IN="bla@some.com;john@home.com"
Теперь я хотел бы разделить строки по ;
разделителю, чтобы у меня было:
ADDR1="bla@some.com"
ADDR2="john@home.com"
Я не обязательно нужен ADDR1
и ADDR2
переменные. Если они являются элементами массива, это даже лучше.
После предложений из ответов, приведенных ниже, я получил следующее:
#!/usr/bin/env bash
IN="bla@some.com;john@home.com"
mails=$(echo $IN | tr ";" "\n")
for addr in $mails
do
echo "> [$addr]"
done
Вывод:
> [bla@some.com]
> [john@home.com]
Было решение, включающее установку Internal_field_separator (IFS) в ;
. Я не уверен, что случилось с этим ответом, как вы IFS
вернетесь к настройкам по умолчанию?
RE: IFS
решение, я попробовал это, и оно работает, я сохраняю старое IFS
и затем восстанавливаю это:
IN="bla@some.com;john@home.com"
OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
echo "> [$x]"
done
IFS=$OIFS
Кстати, когда я пытался
mails2=($IN)
Я получил только первую строку при печати в цикле, без скобок вокруг $IN
это работает.
local IFS=...
где это возможно; (b) -1 дляunset IFS
, это не совсем сбрасывает IFS к его значению по умолчанию, хотя я считаю, что неустановленный IFS ведет себя так же, как значение по умолчанию IFS ($ '\ t \ n'), однако это кажется плохой практикой слепо предполагать, что ваш код никогда не будет вызываться с установленным значением IFS; (c) другая идея состоит в том, чтобы вызывать подоболочку:(IFS=$custom; ...)
при выходе из подоболочки IFS вернется к тому, что было изначально.ruby -e "puts ENV.fetch('PATH').split(':')"
. Если вы хотите остаться чистым, bash не поможет, но проще использовать любой язык сценариев со встроенным разделением.for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
\n
только на пробел. Итак, последняя строкаmails=($(echo $IN | tr ";" " "))
. Так что теперь я могу проверять элементыmails
, используя нотацию массиваmails[index]
или просто повторяя в циклеОтветы:
Вы можете установить переменную внутреннего разделителя полей (IFS), а затем разрешить ее анализ в массив. Когда это происходит в команде, тогда присваивание
IFS
происходит только среде этой отдельной команды (toread
). Затем он анализирует входные данные в соответствии соIFS
значением переменной в массив, который мы затем можем перебрать.Он будет анализировать одну строку элементов, разделенных
;
, помещая ее в массив. Материал для обработки всего$IN
, каждый раз одна строка ввода разделяется;
:источник
IFS
в той же строке, что иread
без точки с запятой или другого разделителя, в отличие от отдельной команды, ограничивает ее этой командой, поэтому она всегда «восстанавливается»; вам не нужно ничего делать вручную.$IN
заключать в кавычки. Ошибка исправлена вbash
4.3.Взято из скриптового массива Bash :
Объяснение:
Эта конструкция заменяет все вхождения
';'
(начальная//
означает глобальную замену) в строкеIN
на' '
(один пробел), а затем интерпретирует строку, разделенную пробелом, как массив (это то, что делают окружающие скобки).Синтаксис, используемый внутри фигурных скобок для замены каждого
';'
символа на' '
символ, называется расширением параметра .Есть несколько распространенных ошибок:
IFS=':'; arrIN=($IN); unset IFS;
IFS=$'\n'; arrIN=($IN); unset IFS;
источник
IN="bla@some.com;john@home.com;*;broken apart"
, Вкратце: этот подход сломается, если ваши токены содержат встроенные пробелы и / или символы. например*
, чтобы токен совпадал с именами файлов в текущей папке.;*;
, то*
он будет расширен до списка имен файлов в текущем каталоге. -1Если вы не возражаете обработать их немедленно, мне нравится делать это:
Вы можете использовать этот тип цикла для инициализации массива, но, вероятно, есть более простой способ сделать это. Надеюсь, это поможет, хотя.
источник
IN="bla@some.com;john@home.com;*;broken apart"
, Вкратце: этот подход сломается, если ваши токены содержат встроенные пробелы и / или символы. например*
, чтобы токен совпадал с именами файлов в текущей папке.Совместимый ответ
Есть много разных способов сделать это в удар,
Тем не менее, важно сначала отметить, что
bash
имеет много специальных функций (так называемых bashisms ), которые не будут работать ни в одном другомракушка,В частности, массивы , ассоциативные массивы и подстановка шаблонов , которые используются в решениях в этом посте, а также в других цепочках , являются ошибками и могут не работать под другими оболочками, которые используют многие люди.
Например: на моем Debian GNU / Linux есть стандартная оболочка под названиемтире; Я знаю многих людей, которые любят использовать другую оболочку под названиемКШ; и есть также специальный инструмент под названиемBusyBox с его собственным интерпретатором оболочки (ясень).
Запрашиваемая строка
Строка, которая будет разбита в приведенном выше вопросе:
Я буду использовать модифицированную версию этой строки, чтобы убедиться, что мое решение устойчиво к строкам, содержащим пробелы, которые могут нарушить другие решения:
Разделить строку на основе разделителя в удар (версия> = 4.2)
В чистом виде
bash
мы можем создать массив с элементами, разделенными временным значением для IFS ( разделитель входного поля ). IFS, помимо прочего, сообщает,bash
какой символ (символы) он должен рассматривать как разделитель между элементами при определении массива:В более новых версиях
bash
, предварив команду с определением МФСА изменяет IFS для этой команды только и сбрасывает его в предыдущее значение сразу же после этого. Это означает, что мы можем сделать выше всего одну строку:Мы можем видеть, что строка
IN
была сохранена в массив с именемfields
, разделенный на точки с запятой:(Мы также можем отобразить содержимое этих переменных, используя
declare -p
:)Обратите внимание, что
read
это самый быстрый способ сделать разделение, потому что нет никаких вызванных вилок или внешних ресурсов.Как только массив определен, вы можете использовать простой цикл для обработки каждого поля (или, вернее, каждого элемента в массиве, который вы сейчас определили):
Или вы можете удалить каждое поле из массива после обработки, используя подход смещения , который мне нравится:
И если вам нужна простая распечатка массива, вам даже не нужно зацикливаться на нем:
Обновление: недавно удар > = 4.4
В новых версиях
bash
вы также можете играть с командойmapfile
:Этот синтаксис сохраняет специальные символы, новые строки и пустые поля!
Если вы не хотите включать пустые поля, вы можете сделать следующее:
С помощью
mapfile
вы также можете пропустить объявление массива и неявно «зацикливаться» на элементах с разделителями, вызывая функцию для каждого:(Примечание:
\0
конец строки формата бесполезен, если вам не нужны пустые поля в конце строки или они отсутствуют.)Или вы можете использовать
<<<
, и в теле функции включить некоторую обработку для удаления новой строки:Разделить строку на основе разделителя в ракушка
Если вы не можете использовать
bash
или если вы хотите написать что-то, что можно использовать во многих различных оболочках, вы часто не можете использовать bashisms - и это включает в себя массивы, которые мы использовали в решениях выше.Однако нам не нужно использовать массивы для циклического перебора «элементов» строки. Существует синтаксис, используемый во многих оболочках для удаления подстрок строки из первого или последнего вхождения шаблона. Обратите внимание, что
*
подстановочный знак обозначает ноль или более символов:(Отсутствие такого подхода в любом опубликованном решении является основной причиной, по которой я пишу этот ответ;)
Как объяснил Score_Under :
Используя приведенный выше синтаксис, мы можем создать подход, в котором мы извлекаем «элементы» подстроки из строки, удаляя подстроки до или после разделителя.
Кодовый блок ниже хорошо работает в удар(включая Mac OS
bash
),тире, КШ, а также BusyBox«s ясень:Радоваться, веселиться!
источник
#
,##
,%
и%%
замены есть то , что ИМО проще объяснение , чтобы помнить (за сколько они удалить)#
и%
удалить кратчайшую строку соответствия, а также##
и%%
удалить самое длинные возможное.IFS=\; read -a fields <<<"$var"
Терпит неудачу на переводы строк и добавить символ новой строки. Другое решение удаляет завершающее пустое поле.for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
Я видел пару ответов со ссылкой на
cut
команду, но все они были удалены. Немного странно, что никто не уточнил это, потому что я думаю, что это одна из наиболее полезных команд для такого типа вещей, особенно для анализа файлов журнала с разделителями.В случае разбиения этого конкретного примера на массив сценариев bash,
tr
возможно, он более эффективен, ноcut
его можно использовать, и он более эффективен, если вы хотите извлечь определенные поля из середины.Пример:
Очевидно, вы можете поместить это в цикл и выполнить итерацию параметра -f для независимого извлечения каждого поля.
Это становится более полезным, когда у вас есть лог-файл с разделителями со строками вроде этого:
cut
очень удобно иметь возможностьcat
этого файла и выбрать конкретное поле для дальнейшей обработки.источник
cut
, это правильный инструмент для работы! Многое очищено, чем любой из этих хакерских оболочек.Это сработало для меня:
источник
Как насчет этого подхода:
Источник
источник
IFS";" && Array=($IN)
$'...'
:IN=$'bla@some.com;john@home.com;bet <d@\ns* kl.com>'
. Затемecho "${Array[2]}"
напечатает строку с новой строкой.set -- "$IN"
также необходимо в этом случае. Да, чтобы предотвратить глобальное расширение, решение должно включатьset -f
.Я думаю, что AWK - лучшая и эффективная команда для решения вашей проблемы. AWK включен по умолчанию почти во все дистрибутивы Linux.
дам
Конечно, вы можете сохранить каждый адрес электронной почты, переопределив поле печати awk.
источник
inode=
в;
, например , с помощьюsed -i 's/inode\=/\;/g' your_file_to_process
, а затем определить ,-F';'
когда применятьawk
, надежду на то, что может помочь вам.источник
IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )
, в этом случае будет получен массив из 8 элементов (элемент для каждого разделенного пробелом слова), а не 2 (элемент для каждой строки, разделеннойarrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )
для достижения этой цели, а также посоветовать изменить IFSIFS=$'\n'
для тех, кто приземлится здесь в будущем и должен разбить строку, содержащую пробелы. (и восстановить его потом). :)Это также работает:
Будьте осторожны, это решение не всегда правильно. Если вы передадите только «bla@some.com», он назначит его как ADD1, так и ADD2.
источник
Другой ответ на ответ Даррона , вот как я это делаю:
источник
IFS=";"
назначение существует только в$(...; echo $IN)
подоболочке; Вот почему некоторые читатели (включая меня) изначально думают, что это не сработает. Я предположил, что весь $ IN был подбит ADDR1. Но ник это правильно; это работает. Причина в том, чтоecho $IN
команда анализирует свои аргументы, используя текущее значение $ IFS, но затем выводит их на стандартный вывод, используя разделитель пробелов, независимо от значения параметра $ IFS. Таким образом, чистый эффект такой, как если бы он звонилread ADDR1 ADDR2 <<< "bla@some.com john@home.com"
(обратите внимание, что ввод не разделен пробелом; -отделен).*
вecho $IN
с расширением некотируемого переменной.В Bash, пуленепробиваемый способ, который будет работать, даже если ваша переменная содержит символы новой строки:
Смотреть:
Хитрость для этого заключается в том, чтобы использовать
-d
опциюread
(разделитель) с пустым разделителем, так чтоread
он вынужден читать все, что ему дают. И мы добавляемread
именно содержимое переменнойin
, без завершающей строки, благодаряprintf
. Обратите внимание, что мы также добавляем разделитель,printf
чтобы убедиться, что переданная строкаread
имеет конечный разделитель. Без негоread
обрезал бы потенциальные конечные пустые поля:конечное пустое поле сохраняется.
Обновление для Bash≥4.4
Начиная с Bash 4.4, встроенная функция
mapfile
(akareadarray
) поддерживает-d
возможность указания разделителя. Отсюда и другой канонический способ:источник
\n
пробелами и*
одновременно. Также нет петель; Переменная массива доступна в оболочке после выполнения (в отличие от ответа с наибольшим количеством голосов). Обратите внимание,in=$'...'
что он не работает с двойными кавычками. Я думаю, что нужно больше голосов.Как насчет этого одного лайнера, если вы не используете массивы:
источник
read -r ...
чтобы, например, два символа «\ t» во входных данных оказались одинаковыми двумя символами в ваших переменных (вместо одного символа табуляции).echo "ADDR1 $ADDR1"\n echo "ADDR2 $ADDR2"
к вашему фрагменту приведет к выводуADDR1 bla@some.com john@home.com\nADDR2
(\ n -IFS
и здесь строки, которые были исправлены вbash
4.3. Цитирование$IN
должно это исправить. (Теоретически,$IN
не подлежит разделению или смещению слова после его расширения, а это означает, что кавычки не должны быть необходимыми. Однако даже в 4.3 остается хотя бы одна ошибка - сообщается и планируется исправить - поэтому цитирование остается хорошим идея.)Без настройки IFS
Если у вас есть только двоеточие, вы можете сделать это:
ты получишь:
источник
Вот чистый 3-х вкладыш:
где
IFS
слова разграничиваются на основе разделителя и()
используются для создания массива . затем[@]
используется для возврата каждого элемента как отдельного слова.Если у вас есть какой-либо код после этого, вам также необходимо восстановить
$IFS
, напримерunset IFS
.источник
$in
кавычек позволяет расширять символы подстановки.Следующая функция Bash / zsh разделяет свой первый аргумент на разделитель, заданный вторым аргументом:
Например, команда
доходность
Этот вывод может, например, передаваться другим командам. Пример:
По сравнению с другими решениями, данное имеет следующие преимущества:
IFS
не переопределяется: из-за динамического определения области действия даже локальных переменных переопределениеIFS
по циклу вызывает утечку нового значения в вызовы функций, выполняемые из цикла.Массивы не используются: для чтения строки в массив
read
необходимо использовать флаг-a
в Bash и-A
zsh.При желании функция может быть помещена в скрипт следующим образом:
источник
help read
:-d delim continue until the first character of DELIM is read, rather than newline
Вы можете применить awk во многих ситуациях
также вы можете использовать это
источник
Существует простой и умный способ, как это:
Но вы должны использовать gnu xargs, BSD xargs не может поддерживать -d delim. Если вы используете Apple Mac, как я. Вы можете установить GNU XARGS:
тогда
источник
Это самый простой способ сделать это.
источник
Здесь есть несколько классных ответов (errator esp.), Но для чего-то аналогичного разделению на другие языки - что я и имел в виду в первоначальном вопросе - я остановился на этом:
Теперь
${a[0]}
и${a[1]}
т. Д., Как и следовало ожидать. Используйте${#a[*]}
для ряда условий. Или, конечно, повторить:ВАЖНАЯ ЗАМЕТКА:
Это работает в тех случаях, когда нет места для беспокойства, что решило мою проблему, но не может решить вашу. Перейти с
$IFS
решением (ями) в этом случае.источник
IN
содержит более двух адресов электронной почты. Пожалуйста, обратитесь к той же идее (но исправлено) в ответе Палиндрома${IN//;/ }
(двойной слеш), чтобы он также работал с более чем двумя значениями. Помните, что любой подстановочный знак (*?[
) будет расширен. И конечное пустое поле будет отброшено.Вывод
Система: Ubuntu 12.04.1
источник
read
здесь и, следовательно, может расстроить остальную часть кода, если таковой имеется.Если нет места, почему бы не это?
источник
Используйте
set
встроенный для загрузки$@
массива:Тогда пусть вечеринка начнется:
источник
set -- $IN
чтобы избежать некоторых проблем с $ IN, начинающимися с тире. Тем не менее, расширение без кавычек$IN
будет расширять символы подстановки (*?[
).Две альтернативы bourne-ish, где ни один не требует массивов bash:
Случай 1 : Делайте это красиво и просто: используйте NewLine в качестве разделителя записей ... например.
Примечание: в этом первом случае ни один подпроцесс не разветвляется, чтобы помочь с манипулированием списком.
Идея: Может быть, стоит использовать NL для внутреннего использования , и преобразовывать его в другой RS только при внешнем генерировании конечного результата .
Случай 2 : использование «;» в качестве разделителя записей ... например.
В обоих случаях под-список может быть составлен в цикле постоянным после завершения цикла. Это полезно при работе со списками в памяти, вместо хранения списков в файлах. {ps сохраняйте спокойствие и продолжайте B-)}
источник
Помимо фантастических ответов, которые уже были предоставлены, если это просто вопрос распечатки данных, которые вы можете использовать
awk
:Это устанавливает разделитель полей на
;
, чтобы он мог перебирать поля сfor
цикла и печатать соответственно.Тестовое задание
С другим входом:
источник
В оболочке Android большинство предложенных методов просто не работают:
Что работает это:
где
//
означает глобальную замену.источник
Вывод:
Объяснение: Простое присваивание с использованием круглых скобок () преобразует список, разделенный точкой с запятой, в массив, если при этом у вас есть правильный IFS. Стандартный цикл FOR обрабатывает отдельные элементы в этом массиве как обычно. Обратите внимание, что список, заданный для переменной IN, должен быть «жестко» заключен в кавычки, то есть с одиночными тиками.
IFS должен быть сохранен и восстановлен, так как Bash не обрабатывает назначение так же, как команда. Альтернативный обходной путь - обернуть назначение внутри функции и вызвать эту функцию с измененным IFS. В этом случае отдельное сохранение / восстановление IFS не требуется. Спасибо за "Бизе" за указание на это.
источник
!"#$%&/()[]{}*? are no problem
ну ... не совсем:[]*?
это глобус персонажи. Так как насчет создания этого каталога и файла: `mkdir '!" # $% &'; Touch '! "# $% & / () [] {} У вас есть хахахаха - нет проблем' и выполнение вашей команды? Простое может быть красивым, но когда оно сломано, оно сломано.mkdir '!"#$%&'; touch '!"#$%&/()[]{} got you hahahaha - are no problem'
. Я должен признать, что они будут создавать только каталог и файл со странными названиями. Затем запускать команды с точнымIN
вы дали:IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'
. Вы увидите, что вы не получите ожидаемый результат. Потому что вы используете метод, подверженный раскрытию пути, чтобы разбить вашу строку.*
,?
,[...]
и даже, еслиextglob
установлен, то!(...)
,@(...)
,?(...)
,+(...)
являются проблемы с этим методом!Ладно, ребята!
Вот мой ответ!
Почему этот подход "лучший" для меня?
По двум причинам:
[] 'S
источник
/etc/os-release
и/etc/lsb-release
должны быть получены, а не проанализированы. Таким образом, ваш метод действительно неверен. Более того, вы не совсем отвечаете на вопрос о том, как разбить строку на разделитель.Однострочник для разделения строки, разделенной ';' в массив это:
Это только устанавливает IFS в подоболочке, поэтому вам не нужно беспокоиться о сохранении и восстановлении его значения.
источник
0: bla@some.com;john@home.com\n 1:
(\ n - новая строка)$IN
котируется, поэтому не подлежит разделению IFS. 3. Подстановка процесса разделяется пробелами, но это может привести к повреждению исходных данных.Возможно, не самое элегантное решение, но работает с
*
пробелами:Выходы
Другой пример (разделители в начале и в конце):
В основном это удаляет каждый символ, кроме
;
создания,delims
например.;;;
, Затем он выполняетfor
цикл от1
до,number-of-delimiters
как считается${#delims}
. Последний шаг - это безопасное$i
использованиеcut
.источник