Split bash: Bash Split String Examples – Linux Hint
Как сделать split строкой на разделителе в Bash?
Совместимый ответ
Есть много различных способов сделать это в bash .
Однако прежде всего важно отметить, что bash
имеет много специальных функций (так называемых башизмов ), которые не будут работать ни в одном другом shell .
В частности, массивы , ассоциативные массивы и замена шаблонов , которые используются в решениях в этом посте , а также в других потоках, являются башизмами и могут не работать под другими оболочками , которые используют многие люди.
Например: на моем Debian GNU/Linux есть стандартный shell под названием dash ; я знаю многих людей , которые любят использовать другой shell под названием ksh ; а также есть специальный инструмент busybox с его собственным интерпретатором shell ( ash ).
Запрошенная строка
Строка, которая должна быть split в приведенном выше вопросе, такова:
IN="bla@some. com;[email protected]"
Я буду использовать модифицированную версию этой строки, чтобы убедиться, что мое решение устойчиво к строкам, содержащим whitespace, которые могут нарушить другие решения:
IN="[email protected];[email protected];Full Name <[email protected]>"
Строка Split на основе разделителя в bash (версия >=4.2)
В pure bash
мы можем создать массив с элементами split по временному значению для IFS ( разделитель полей ввода ). The IFS , среди прочего, сообщает bash
, какой символ(Ы) он должен рассматривать как разделитель между элементами при определении массива:
IN="[email protected];[email protected];Full Name <[email protected]>"
# save original IFS value so we can restore it later
oIFS="$IFS"
IFS=";"
declare -a fields=($IN)
IFS="$oIFS"
unset oIFS
В более новых версиях bash
префикс команды с определением IFS изменяет значение IFS только для этой команды и сразу же после этого сбрасывает его до предыдущего значения. IN=
# fields=([0]=»[email protected]» [1]=»[email protected]» [2]=»Full Name <[email protected]>»)
# IN=’[email protected];[email protected];Full Name <[email protected]>’
(Мы также можем отобразить содержимое этих переменных с помощью declare -p
🙂
declare -p IN fields
# declare -- IN="[email protected];[email protected];Full Name <[email protected]>"
# declare -a fields=([0]="[email protected]" [1]="[email protected]" [2]="Full Name <[email protected]>")
Обратите внимание, что read
-это самый быстрый способ сделать split, потому что нет никаких вилок или внешних ресурсов, вызываемых.
Как только массив определен, вы можете использовать простой цикл для обработки каждого поля (или, скорее, каждого элемента в массиве, который вы теперь определили):
# `"${fields[@]}"` expands to return every element of `fields` array as a separate argument
for x in "${fields[@]}" ;do
echo "> [$x]"
done
# > [bla@some. com]
# > [[email protected]]
# > [Full Name <[email protected]>]
Или вы можете удалить каждое поле из массива после обработки, используя смещающий подход, который мне нравится:
while [ "$fields" ] ;do
echo "> [$fields]"
# slice the array
fields=("${fields[@]:1}")
done
# > [[email protected]]
# > [[email protected]]
# > [Full Name <[email protected]>]
И если вы просто хотите получить простую распечатку массива, вам даже не нужно перебирать его:
printf "> [%s]\n" "${fields[@]}"
# > [[email protected]]
# > [[email protected]]
# > [Full Name <[email protected]>]
Обновление: недавнее bash >= 4.4
В более новых версиях bash
вы также можете играть с командой mapfile
:
mapfile -td \; fields < <(printf "%s\0" "$IN")
Этот синтаксис сохраняет специальные символы, новые строки и пустые поля!
Если вы не хотите включать пустые поля, вы можете сделать следующее:
mapfile -td \; fields <<<"$IN"
fields=("${fields[@]%$'\n'}") # drop '\n' added by '<<<'
С помощью функции mapfile
вы также можете пропустить объявление массива и неявно «loop» над разделенными элементами , вызывая функцию для каждого из них:
myPubliMail() {
printf "Seq: %6d: Sending mail to '%s'. .." $1 "$2"
# mail -s "This is not a spam..." "$2" </path/to/body
printf "\e[3D, done.\n"
}
mapfile < <(printf "%s\0" "$IN") -td \; -c 1 -C myPubliMail
(Примечание: \0
в конце строки формата бесполезен, если вы не заботитесь о пустых полях в конце строки или их нет.)
mapfile < <(echo -n "$IN") -td \; -c 1 -C myPubliMail
# Seq: 0: Sending mail to '[email protected]', done.
# Seq: 1: Sending mail to '[email protected]', done.
# Seq: 2: Sending mail to 'Full Name <[email protected]>', done.
Или вы можете использовать <<<
, и в теле функции включить некоторую обработку, чтобы удалить новую строку, которую она добавляет:
myPubliMail() {
local seq=$1 dest="${2%$'\n'}"
printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
# mail -s "This is not a spam..." "$dest" </path/to/body
printf "\e[3D, done.\n"
}
mapfile <<<"$IN" -td \; -c 1 -C myPubliMail
# Renders the same output:
# Seq: 0: Sending mail to 'bla@some. com', done.
# Seq: 1: Sending mail to '[email protected]', done.
# Seq: 2: Sending mail to 'Full Name <[email protected]>', done.
Строка Split на основе разделителя в shell
Если вы не можете использовать bash
, или если вы хотите написать что-то, что может быть использовано во многих различных оболочках, вы часто не можете использовать башизмы -и это включает массивы, которые мы использовали в решениях выше.
Однако нам не нужно использовать массивы для циклического перебора «elements» строки. Существует синтаксис, используемый во многих оболочках для удаления подстрок строки из первого или последнего вхождения шаблона. Обратите внимание, что *
-это подстановочный знак, который обозначает ноль или более символов:
(Отсутствие этого подхода в любом решении, опубликованном до сих пор, является основной причиной, по которой я пишу этот ответ 😉
${var#*SubStr} # drops substring from start of string up to first occurrence of `SubStr`
${var##*SubStr} # drops substring from start of string up to last occurrence of `SubStr`
${var%SubStr*} # drops substring from last occurrence of `SubStr` to end of string
${var%%SubStr*} # drops substring from first occurrence of `SubStr` to end of string
Как объяснил Score_Under :
#
и%
удаляют максимально короткую совпадающую подстроку из начала и конца строки соответственно, а также
##
и%%
удаляют максимально длинную совпадающую подстроку.
Используя приведенный выше синтаксис, мы можем создать подход, при котором мы извлекаем подстроку «elements» из строки, удаляя подстроки до или после разделителя.
Приведенный ниже кодовый блок хорошо работает в bash (включая Mac OS bash
), dash , ksh и busybox ‘s ash :
IN="[email protected];[email protected];Full Name <[email protected]>"
while [ "$IN" ] ;do
# extract the substring from start of string up to delimiter.
# this is the first "element" of the string.
iter=${IN%%;*}
echo "> [$iter]"
# if there's only one element left, set `IN` to an empty string.
# this causes us to exit this `while` loop.
# else, we delete the first "element" of the string from IN, and move onto the next.
[ "$IN" = "$iter" ] && \
IN='' || \
IN="${IN#*;}"
done
# > [[email protected]]
# > [[email protected]]
# > [Full Name <[email protected]>]
Получайте удовольствие!
Как разделить строку в скрипте Bash
В этой статье вы научитесь разбивать строку на массив в скрипте Bash.
Допустим, у вас есть длинная строка с несколькими словами, разделенными запятой или подчеркиванием. Вы хотите разбить эту строку и извлечь отдельные слова.
Вы можете разделить строки в bash, используя разделитель внутренних полей (IFS) и команду чтения, или вы можете использовать команду обрезки. Позвольте нам показать вам, как это сделать на примерах.
Метод 1: Разделить строку с помощью команды чтения в Bash
Вот наш пример сценария для разделения строки с помощью команды read:
#!/bin/bash # # Скрипт для разделения строки на основе разделителя my_string="Ubuntu;Linux Mint;Debian;Arch;Fedora" IFS=';' read -ra my_array <<< "$my_string" # Печать разделенной строки for i in "${my_array[@]}" do echo $i done
Часть, которая разбивает строку, находится здесь:
IFS=';' read -ra my_array <<< "$my_string"
IFS определяет разделитель, по которому вы хотите разбить строку. В нашем случае это точка с запятой. Это может быть что угодно: пробел, табуляция, запятая или даже алфавит.
IFS в команде read разделяет входные данные в разделителе. Команда read читает необработанный ввод (опция -r), поэтому интерпретирует обратную косую черту буквально, а не обрабатывает их как escape-символ. Опция -a с командой read сохраняет слово read в массиве.
Проще говоря, длинная строка разбивается на несколько слов, разделенных разделителем, и эти слова хранятся в массиве.
Теперь вы можете получить доступ к массиву, чтобы получить любое слово, которое вы хотите, или использовать цикл for в bash, чтобы напечатать все слова одно за другим, как мы делали в приведенном выше сценарии.
Вот вывод вышеприведенного скрипта:
Ubuntu
Linux Mint
Debian
Arch
Fedora
Способ 2: разделить строку с помощью команды trim в Bash
Это пример разделения строки bash с использованием команды trim (tr):
#! / bin / bash # # Скрипт для разделения строки на основе разделителя
my_string="Ubuntu;Linux Mint;Debian;Arch;Fedora" my_array=($(echo $my_string | tr ";" "\n")) #Print the split string for i in "${my_array[@]}" do echo $i done
Этот пример почти такой же, как и предыдущий. Вместо команды чтения, команда trim используется для разделения строки на разделителе.
Проблема с этим подходом состоит в том, что элемент массива разделен на «пробел». Из-за этого такие элементы, как «Linux Mint», будут рассматриваться как два слова.
Вот вывод вышеприведенного скрипта:
Ubuntu
Linux
Mint
Debian
Arch
Fedora
Вот почему мы предпочитаем первым способом разбивать строку в bash.
Мы надеемся, что эта краткая статья по bash помогла вам разбить строку.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Как разбить строку на разделителе в Bash?
Совместимый ответ
К этому вопросу SO, в bash уже есть много другого способа сделать это . Но Баш имеет множество специальных функций, так называемые bashism , которые хорошо работают, но это не будет работать в любой другой оболочке .
В частности, массивы , ассоциативный массив и подстановка шаблонов являются чистыми bashisms и могут не работать под другими оболочками .
На моем Debian GNU / Linux есть стандартная оболочка под названием dash , но я знаю многих людей, которые любят использовать ksh .
Наконец, в очень маленькой ситуации есть специальный инструмент под названием busybox со своим интерпретатором оболочки ( зола ).
Запрошенная строка
Образец строки в вопросе SO:
IN="[email protected];[email protected]"
Поскольку это может быть полезно с пробелами, и поскольку пробелы могут изменять результат подпрограммы, я предпочитаю использовать эту примерную строку:
IN="[email protected];[email protected];Full Name <[email protected]>"
Разделить строку на основе разделителя в bash (версия> = 4.2)
При чистом bash мы можем использовать массивы и IFS :
var="[email protected];[email protected];Full Name <[email protected]>"
oIFS="$IFS"
IFS=";"
declare -a fields=($var)
IFS="$oIFS"
unset oIFS
IFS=\; read -a fields <<<"$IN"
Использование этого синтаксиса в недавнем bash не изменяется $IFS
для текущего сеанса, но только для текущей команды:
set | grep ^IFS=
IFS=$' \t\n'
Теперь строка var
разделяется и сохраняется в массив (named fields
):
set | grep ^fields=\\\|^var=
fields=([0]="bla@some. com" [1]="[email protected]" [2]="Full Name <[email protected]>")
var='[email protected];[email protected];Full Name <[email protected]>'
Мы можем запросить переменный контент с помощью declare -p
:
declare -p IN fields
declare -- IN="[email protected];[email protected];Full Name <[email protected]>"
declare -a fields=([0]="[email protected]" [1]="[email protected]" [2]="Full Name <[email protected]>")
read
это самый быстрый способ сделать раскол, потому что нет вилок и внешних ресурсов.
Оттуда вы можете использовать синтаксис, который вы уже знаете для обработки каждого поля:
for x in "${fields[@]}";do
echo "> [$x]"
done
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]
или отбросить каждое поле после обработки (мне нравится этот подход сдвига ):
while [ "$fields" ] ;do
echo "> [$fields]"
fields=("${fields[@]:1}")
done
> [bla@some. com]
> [[email protected]]
> [Full Name <[email protected]>]
или даже для простой распечатки (более короткий синтаксис):
printf "> [%s]\n" "${fields[@]}"
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]
Обновление: недавнее bash > = 4.4
Вы можете играть с mapfile
:
mapfile -td \; fields < <(printf "%s\0" "$IN")
Этот синтаксис сохраняет специальные символы, новые строки и пустые поля!
Если вам не нужны пустые поля, вы можете:
mapfile -td \; fields <<<"$IN"
fields=("${fields[@]%$'\n'}") # drop '\n' added by '<<<'
Но вы можете использовать поля через функцию:
myPubliMail() {
printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
# mail -s "This is not a spam..." "$2" </path/to/body
printf "\e[3D, done.\n"
}
mapfile < <(printf "%s\0" "$IN") -td \; -c 1 -C myPubliMail
(Nota: \0
в конце строки формата бесполезны, пока вам не нужны пустые поля в конце строки)
mapfile < <(echo -n "$IN") -td \; -c 1 -C myPubliMail
Будет выглядеть примерно так:
Seq: 0: Sending mail to 'bla@some. com', done.
Seq: 1: Sending mail to '[email protected]', done.
Seq: 2: Sending mail to 'Full Name <[email protected]>', done.
Или Drop newline, добавленный <<<
синтаксисом bash в функции:
myPubliMail() {
local seq=$1 dest="${2%$'\n'}"
printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
# mail -s "This is not a spam..." "$dest" </path/to/body
printf "\e[3D, done.\n"
}
mapfile <<<"$IN" -td \; -c 1 -C myPubliMail
Будет выдавать тот же результат:
Seq: 0: Sending mail to '[email protected]', done.
Seq: 1: Sending mail to '[email protected]', done.
Seq: 2: Sending mail to 'Full Name <[email protected]>', done.
Разделить строку на основе разделителя в оболочке
Но если бы вы написать что — то полезное под многими оболочками, вы должны не использовать bashisms .
Существует синтаксис, используемый во многих оболочках, для разделения строки на первое или последнее вхождение подстроки:
${var#*SubStr} # will drop begin of string up to first occur of `SubStr`
${var##*SubStr} # will drop begin of string up to last occur of `SubStr`
${var%SubStr*} # will drop part of string from last occur of `SubStr` to the end
${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end
(Отсутствие этого является основной причиной публикации моего ответа;)
Как указано Score_Under :
#
и%
удалите кратчайшую совпадающую строку, и
##
и%%
удалить максимально возможное время.где
#
и##
среднее слева (начало) строки, и
%
и%%
meand справа (конец) строки.
Этот небольшой пример скрипта хорошо работает под bash , dash , ksh , busybox и был протестирован также в bash для Mac OS:
var="[email protected];[email protected];Full Name <[email protected]>"
while [ "$var" ] ;do
iter=${var%%;*}
echo "> [$iter]"
[ "$var" = "$iter" ] && \
var='' || \
var="${var#*;}"
done
> [[email protected]]
> [[email protected]]
> [Full Name <[email protected]>]
Повеселись!
Автор: F. Hauri
Размещён: 13.04.2013 02:20
Оболочка
— как разбить строку по разделителю в Bash?
Совместимый ответ
В bash есть много разных способов сделать это.
Однако сначала важно отметить, что bash
имеет множество специальных функций (так называемые bashisms ), которые не будут работать ни в одной другой оболочке.
В частности, массивов , ассоциативных массивов и подстановки шаблонов , которые используются в решениях в этом посте, а также в других в потоке, являются башизмами и могут не работать в других оболочках , которые многие люди используют.
Например: на моем Debian GNU / Linux есть стандартная оболочка , называемая dash; Я знаю многих людей, которым нравится использовать другую оболочку под названием ksh; а также есть специальный инструмент под названием busybox со своим собственным интерпретатором оболочки (ash).
Запрошенная строка
Строка, которую нужно разделить в вопросе выше:
IN = "[email protected]; [email protected]"
Я буду использовать модифицированную версию этой строки, чтобы убедиться, что мое решение устойчиво к строкам, содержащим пробелы, что может нарушить работу других решений:
IN = "bla @ some.com; [email protected]; полное имя org> "
Разделить строку на основе разделителя в bash (версия> = 4.2)
В чистом bash
мы можем создать массив с элементами, разделенными временным значением для IFS (разделитель поля ввода ). IFS, помимо прочего, сообщает bash
, какие символы следует рассматривать как разделители между элементами при определении массива:
IN = "bla @ some.com; [email protected]; полное имя "
# сохранить исходное значение IFS, чтобы мы могли восстановить его позже
oIFS = "$ IFS"
IFS = ";"
объявить -a поля = ($ IN)
IFS = "$ oIFS"
сбросить oIFS
В более новых версиях bash
префикс команды с определением IFS изменяет IFS для этой команды только на и сразу после этого сбрасывает его на предыдущее значение. Это означает, что мы можем сделать это всего в одной строке:
IFS = \; read -a fields <<< "$ IN"
# после этой команды IFS возвращается к своему предыдущему значению (здесь по умолчанию):
набор | grep ^ IFS =
# IFS = $ '\ t \ n'
Мы видим, что строка IN
была сохранена в массиве с именем fields
, разделенном точками с запятой:
набор | grep ^ fields = \\\ | ^ IN =
# fields = ([0] = "bla @ some. com "[1] =" [email protected] "[2] =" Полное имя ")
# IN='[email protected]; [email protected]; Полное имя '
(Мы также можем отобразить содержимое этих переменных, используя declare -p
🙂
объявить поля -p IN
# declare - IN = "[email protected]; [email protected]; Полное имя "
# declare -a fields = ([0] = "[email protected]" [1] = "[email protected]" [2] = "Полное имя ")
Обратите внимание, что read
- это самый быстрый способ для разделения, потому что нет форков или внешних ресурсов.
После того, как массив определен, вы можете использовать простой цикл для обработки каждого поля (или, скорее, каждого элемента в массиве, который вы теперь определили):
# `" $ {fields [@]} "` расширяется, чтобы вернуть каждый элемент массива `fields` как отдельный аргумент
для x в "$ {fields [@]}"; делаем
echo "> [$ x]"
сделано
#> [bla@some. com]
#> [[email protected]]
#> [Полное имя ]
Или вы можете удалить каждое поле из массива после обработки, используя подход со смещением , который мне нравится:
пока ["$ fields"]; делать
echo "> [$ fields]"
# разрезать массив
fields = ("$ {fields [@]: 1}")
сделано
#> [bla @ some.com]
#> [[email protected]]
#> [Полное имя ]
И если вам просто нужна простая распечатка массива, вам даже не нужно его перебирать:
printf "> [% s] \ n" "$ {fields [@]}"
#> [[email protected]]
#> [[email protected]]
#> [Полное имя ]
Обновление
: недавний bash> = 4.4
В более новых версиях bash
вы также можете играть с командой mapfile
:
файл карты -td \; поля <<(printf "% s \ 0" "$ IN")
Этот синтаксис сохраняет специальные символы, символы новой строки и пустые поля!
Если вы не хотите включать пустые поля, вы можете сделать следующее:
файл карты -td \; поля <<< "$ IN"
fields = ("$ {fields [@]% $ '\ n'}") # drop '\ n' добавлен с помощью '<<<'
С mapfile
вы также можете пропустить объявление массива и неявно «зацикливать» элементы с разделителями, вызывая функцию для каждого:
myPubliMail () {
printf "Seq:% 6d: отправка почты на '% s'. .. "$ 1" $ 2 "
# mail -s "Это не спам ..." "$ 2" path / to / body
printf "\ e [3D, готово. \ n"
}
mapfile <<(printf "% s \ 0" "$ IN") -td \; -c 1 -C myPubliMail
(Примечание: \ 0
в конце строки формата бесполезно, если вам не нужны пустые поля в конце строки или они отсутствуют.)
файл карты <<(echo -n "$ IN") -td \; -c 1 -C myPubliMail
# Seq: 0: отправка почты на '[email protected]', готово.
# Seq: 1: отправка почты на адрес 'john @ home.com ', готово.
# Seq: 2: Отправка почты на «Полное имя », готово.
Или , вы можете использовать <<<
, а в теле функции включить некоторую обработку для удаления добавляемой новой строки:
myPubliMail () {
local seq = $ 1 dest = "$ {2% $ '\ n'}"
printf "Seq:% 6d: Отправка почты на '% s' ..." $ seq "$ dest"
# mail -s "Это не спам ..." "$ dest" path / to / body
printf "\ e [3D, готово. \ n"
}
mapfile <<< "$ IN" -td \; -c 1 -C myPubliMail
# Отображает тот же результат:
# Seq: 0: отправка почты на адрес 'bla @ some. com ', готово.
# Seq: 1: Отправка почты на адрес '[email protected]', готово.
# Seq: 2: Отправка почты на «Полное имя », готово.
Разделить строку на основе разделителя в оболочке
Если вы не можете использовать bash
, или если вы хотите написать что-то, что можно использовать во многих разных оболочках, вы часто не можете использовать bashisms - и это включает в себя массивы, которые мы использовали в решениях выше.
Однако нам не нужно использовать массивы для циклического перебора «элементов» строки.Во многих оболочках используется синтаксис для удаления подстрок строки из первых или последних вхождений шаблона. Обратите внимание, что *
- это подстановочный знак, обозначающий ноль или более символов:
(Отсутствие этого подхода в любом опубликованном решении является основной причиной, по которой я пишу этот ответ;)
$ {var # * SubStr} # отбрасывает подстроку от начала строки до первого появления `SubStr`
$ {var ## * SubStr} # отбрасывает подстроку от начала строки до последнего вхождения `SubStr`
$ {var% SubStr *} # отбрасывает подстроку от последнего вхождения `SubStr` до конца строки
$ {var %% SubStr *} # отбрасывает подстроку от первого вхождения `SubStr` до конца строки
Как объяснено Score_Under:
#
и%
удалить самую короткую подходящую подстроку из начала и конца строки соответственно, и
##
и%%
удаляют самую длинную подходящую подстроку.
Используя приведенный выше синтаксис, мы можем создать подход, при котором мы извлекаем «элементы» подстроки из строки, удаляя подстроки до или после разделителя.
Приведенный ниже кодовый блок хорошо работает в bash (включая Mac OS bash
), dash, ksh и ash:
.
IN = "[email protected]; [email protected]; Полное имя "
в то время как ["$ IN"]; делать
# извлекаем подстроку от начала строки до разделителя.
# это первый "элемент" строки.iter = $ {IN %%; *}
echo "> [$ iter]"
# если остался только один элемент, установите IN в пустую строку.
# это заставляет нас выйти из цикла `while`.
# иначе, мы удаляем первый "элемент" строки из IN и переходим к следующему.
["$ IN" = "$ iter"] && \
IN = '' || \
IN = "$ {IN # *;}"
сделано
#> [[email protected]]
#> [[email protected]]
#> [Полное имя ]
Удачи!
разделение строки на массив в bash с табуляцией в качестве разделителя
Назначение массива tmp = ($ {line ///})
разбивает значение на любые символы, содержащиеся в IFS
, который по умолчанию включает табуляцию, и пробелы и символы новой строки. (Я не вижу, что делает пустая подстановка.) Чтобы разделить только на вкладки, установите IFS
на это:
foo = $ 'a \ tk \ testis \ tadult \ tmale \ t8 week \ tRNA'
IFS = $ '\ t'
tmp = ($ foo)
эхо "$ {tmp [5]}"
Хотя это по-прежнему оставляет проблему с глобализацией, и поскольку вы уже используете при чтении
, вы можете использовать read -a tmp
(только в Bash замените -a
на -A
на ksh / zsh / yash), он разбивает входную строку на основе IFS
и сохраняет полученные поля как элементы именованного массива:
$, а IFS = $ '\ t' читать -r -a tmp; делать
эхо "$ {tmp [5]}"
done <<< $ 'a \ tk \ testis \ tadult \ tmale \ t8 week \ tRNA'
Это печатает 8 недель
.Другой положительный момент заключается в том, что изменение в IFS
действует только на время чтения , а не для остальной части скрипта.
Однако учтите, что при чтении
удаляет пустые поля при использовании табуляции в качестве разделителя. В zsh
вы можете заменить IFS = $ '\ t'
на IFS = $ '\ t \ t'
, чтобы этого не произошло.
Конечно, если мы знаем количество / значение полей, мы могли бы просто прочитать
разделить их на отдельные именованные переменные:
... IFS = $ '\ t' читать -r col1 col2 col3 ...
Или, если вы хотите напечатать только этот один столбец, используйте cut
:
вырезать -d $ '\ t' -f 6
Если у вас есть пустые столбцы, cut -d $ '\ t'
и IFS = $ '\ t'
имеют разное поведение по отношению к ним. Cut будет рассматривать каждую отдельную вкладку как отдельный разделитель, в то время как прочитает
будет рассматривать последовательные вкладки как просто одиночный разделитель . То есть строка foo
будет читаться как всего два столбца при при чтении
, но три столбца при вырезают
.
Вы не можете изменить это для вкладок, но печатаемые символы всегда распознаются как отдельные разделители, поэтому вы можете изменить вкладки на какой-либо символ, который не отображается в данных, а затем использовать его в качестве разделителя, например ... | tr '\ t': | IFS =: read -r -a tmp
или около того.
bash - Разделить строку с помощью IFS
В старых версиях bash
вам приходилось заключать переменные в кавычки после <<<
. Это было исправлено в 4.4. В более старых версиях переменная разделялась на IFS, а полученные слова объединялись в пространстве перед сохранением во временном файле, который составляет перенаправление <<<
.
В версии 4.2 и ранее при перенаправлении встроенных команд, таких как , считывалось
или , команда
, это разделение даже принимало IFS для этой встроенной функции (это исправлено в 4. 3):
$ bash-4.2 -c 'a = a.b.c.d; IFS =. читать x <<< $ a; эхо "$ x" '
а б в г
$ bash-4.2 -c 'a = a.b.c.d; IFS =. кошка <<< $ a '
a.b.c.d
$ bash-4.2 -c 'a = a.b.c.d; IFS =. команда cat <<< $ a '
а б в г
Тот, который исправлен в 4.3:
$ bash-4.3 -c 'a = a.b.CD; IFS =. читать x <<< $ a; эхо "$ x" '
a.b.c.d
Но $ a
все еще подлежит разделению на слова:
$ bash-4.3 -c 'a = a.b.c.d; IFS = .; читать x <<< $ a; эхо "$ x" '
а б в г
В 4.4:
$ bash-4.4 -c 'a = a.b.c.d; IFS = .; читать x <<< $ a; эхо "$ x" '
a.b.c.d
Для переносимости на более старые версии укажите вашу переменную (или используйте zsh
, где это <<<
происходит в первую очередь и у него нет этой проблемы)
$ bash-любая-версия -c 'a = a.b.c.d; IFS = .; читать x <<< "$ a"; эхо "$ x" '
a.b.c.d
Обратите внимание, что такой подход к разделению строки работает только для строк, не содержащих символов новой строки. Также обратите внимание, что a..b.c.
будет разделено на "a"
, ""
, "b"
, "c"
(без пустого последнего элемента).
Для разделения произвольных строк вместо этого можно использовать оператор split + glob (что сделает его стандартным и позволит избежать сохранения содержимого переменной во временном файле, как это делает <<<
):
var = 'a.новый
line..b.c. '
set -o noglob # отключить глобус
IFS =.
set - $ var '' # split + glob
для меня
printf 'элемент: <% s> \ n' "$ i"
сделано
или:
array = ($ var '') # в оболочках с поддержкой массивов
''
- сохранить конечный пустой элемент, если таковой имеется. Это также разделит пустую переменную $ var
на один пустой элемент.
Или используйте оболочку с соответствующим оператором разделения:
zsh
:массив = ($ {(s :. :) var} # удаляет пустые элементы array = ("$ {(@ s:. :) var}") # сохраняет пустые элементы
RC
:array = `` (.) {Printf% s $ var} # удаляет пустые элементы
рыб
set array (разделение строк. - $ var) # не для многострочного $ var
разделенная страница Man - разделенная страница Linux
- Linux - SS64.com
Разбиение файла на части фиксированного размера, создание выходных файлов, содержащих
последовательные разделы INPUT (стандартный ввод, если ничего не задано или INPUT равен '-')
Синтаксис разделить [ options ] [ INPUT [ PREFIX ]] Опции - ЛИНИЙ -l ЛИНИЙ --lines = ЛИНИЙ Поместите LINES строк из INPUT в каждый выходной файл.-b БАЙТОВ --bytes = BYTES Поместите первые байтов байтов из INPUT в каждый выходной файл. Добавление 'b' умножает БАЙТОВ, на 512, 'k' на 1024 и 'm' на 1048576. -C БАЙТОВ --line-bytes = БАЙТОВ Поместите в каждый выходной файл столько полных строк INPUT, сколько возможно без превышения байтов BYTES. Для строк длиннее BYTES байт, поместите BYTES байт в каждый выходной файл, пока не станет меньше Остались байты BYTES в строке, затем продолжаем нормально.БАЙТОВ имеет тот же формат, что и для опции --bytes. --подробный Напишите диагностику стандартной ошибки непосредственно перед каждым выходным файлом открыт.
По умолчанию, split помещает 1000 строк из INPUT (или что-то еще.
осталось для последнего раздела) в каждый выходной файл.
Имена выходных файлов состоят из PREFIX (по умолчанию 'x'), за которыми следует группа
букв 'aa', 'ab' и т. д., так что объединение выходных файлов в
отсортированный по имени файла дает исходный входной файл.
Если требуется более 676 выходных файлов, для 'split' используются 'zaa', 'zab' и т. Д.
Примеры
Разделите файл demo.zip на несколько файлов по 100 МБ:
$ split -b 100m demo.zip
Выходным файлам будут присвоены имена из трех букв, начинающиеся с xaa, xab,… для их повторной сборки выберите файлы в алфавитном порядке:
$ cat 'ls x *'> demo2.zip
«Человек, который устал от Лондона, устал искать место для парковки» ~ Пол Теру
Связанные команды linux:
csplit - Разделить файл на части, определяемые контекстом.
cut - Разделение файла на несколько частей.
fmt - переформатировать текст абзаца.
fold - Перенос строк ввода по указанной ширине.
head - выводит первую часть файла (ов).
join - Соединить строки в общем поле.
paste - Объединить строки файлов.
Эквивалентные команды Windows:
FC / lb - Сравните два файла.
Авторские права © 1999-2021 SS64.com
Некоторые права защищены.
Как разбить строку на массив в Bash [Самый простой способ]
Допустим, у вас есть длинная строка, состоящая из нескольких слов, разделенных запятой или подчеркиванием. Вы хотите разделить эту строку и извлечь отдельные слова.
Вы можете разделить строки в bash, используя внутренний разделитель полей (IFS) и команду чтения, или вы можете использовать команду tr. Позвольте мне показать вам, как это сделать, на примерах.
Метод 1. Разделение строки с помощью команды чтения в Bash
Вот мой пример сценария для разделения строки с помощью команды чтения:
#! / Bin / bash
#
# Скрипт для разделения строки по разделителю
my_string = "Ubuntu; Linux Mint; Debian; Arch; Fedora"
IFS = ';' читать -ra my_array <<< "$ my_string"
# Распечатать разделенную строку
для i в "$ {my_array [@]}"
делать
эхо $ я
done
Часть, которая разделяет строку, находится здесь:
IFS = ';' read -ra my_array <<< "$ my_string"
Позвольте мне вам это объяснить.IFS определяет разделитель, по которому вы хотите разделить строку. В моем случае это точка с запятой. Это может быть что угодно, например пробел, табуляция, запятая или даже буква.
IFS в команде чтения разделяет ввод по разделителю. Команда чтения считывает необработанный ввод (опция -r), таким образом, обратная косая черта интерпретируется буквально вместо того, чтобы рассматривать их как escape-символ. Параметр -a с командой чтения сохраняет прочитанное слово в массиве в bash.
В более простых словах длинная строка разбивается на несколько слов, разделенных разделителем, и эти слова хранятся в массиве.
Теперь вы можете получить доступ к массиву, чтобы получить любое слово, которое пожелаете, или использовать цикл for в bash для печати всех слов одно за другим, как я сделал в приведенном выше сценарии.
Вот результат выполнения сценария выше:
Ubuntu
Linux Mint
Debian
Арка
Fedora
Метод 2: Разделение строки с помощью команды tr в Bash
Это пример разделения строки bash с помощью команды tr (translate):
#! / Bin / bash
#
# Скрипт для разделения строки по разделителю
my_string = "Ubuntu; Linux Mint; Debian; Arch; Fedora"
my_array = ($ (echo $ my_string | tr ";" "\ n"))
# Распечатать разделенную строку
для i в "$ {my_array [@]}"
делать
эхо $ я
done
Этот пример почти такой же, как и предыдущий. Вместо команды чтения используется команда tr для разделения строки по разделителю.
Проблема с этим подходом состоит в том, что элементы массива разделены на «разделитель пробелов». По этой причине такие элементы, как «Linux Mint», будут рассматриваться как два слова.
Вот результат выполнения сценария выше:
Ubuntu
Linux
Мята
Debian
Арка
Fedora
Вот почему я предпочитаю первый метод разделения строки в bash.
Я надеюсь, что это краткое руководство по bash помогло вам разделить строку.В соответствующем посте вы также можете прочитать о сравнении строк в bash.
Разделение больших файлов на несколько файлов меньшего размера в Unix
Чтобы разделить большие файлы на файлы меньшего размера в Unix, используйте
разделить команду
. В командной строке Unix введите:
разделить [параметры] префикс имени файла
Замените filename
именем большого файла, который вы хотите разделить. Замените префикс
именем, которое вы хотите давать маленьким выходным файлам.Вы можете исключить [параметры]
или заменить его одним из следующих:
-л льняной номер -b байтов
Если вы используете опцию -l
(нижний регистр L), замените бельевое число
на количество строк, которое вы хотите в каждом из файлов меньшего размера (по умолчанию 1000). Если вы используете
-b
, замените байтов
на количество байтов, которое вы хотите в каждом из меньших файлов.
Команда split
даст каждому создаваемому выходному файлу имя с префиксом
с добавленным к концу расширением, которое указывает его порядок.По умолчанию команда split
добавляет
aa
в первый выходной файл, переходя по алфавиту до zz
для последующих файлов. Если вы не укажете префикс, в большинстве систем используется x
.
Примеры
- В этом простом примере предположим, что
myfile
состоит из 3000 строк:разделить myfile
Это выведет три файла по 1000 строк:
xaa
,
xab
иxac
. - Следующий пример более сложный, работая с тем же файлом:
split -l 500 сегмент myfile
Будет выведено шесть файлов по 500 строк:
segmentaa
,
segmentab
,segmentac
,
сегментов
,сегментов
и
сегментaf
. - Наконец, предположим, что
myfile
- это файл размером 160 КБ:разделить -b 40k сегмент myfile
Будет выведено четыре файла по 40 КБ:
segmentaa
,
segmentab
,segmentac
и
сегмент
.
Для получения дополнительной информации обратитесь к странице руководства по команде split
. В командной строке Unix введите:
человек сплит
Вы также можете изучить команду csplit
, которая разделяет файлы в зависимости от контекста. Для получения дополнительной информации см. Справочную страницу для команды csplit
. В командной строке Unix введите:
человек csplit
Pooja16Fartyal / Bash-split: разделение файла по размеру и длине без потери данных
Характеристика:
Этот модуль используется для разделения большого файла на несколько частей.
Описание:
- Он включает файл сценария оболочки, то есть split.sh
- split.sh: он включает код для разделения большого CSV (с разделителями-запятыми, значения с разделителями-запятыми) и TXT (текст с разделителями-табуляторами) на несколько файлов.
Команда запуска:
Откройте командную строку / Git Bash, перейдите в папку, в которой доступен файл сценария, и выполните следующую команду
bash split.sh -file = [файл для разделения] - [идентификатор] = [количество строк / номера записи / размер]
Команда | Описание |
---|---|
Баш | Bash - это оболочка Unix и командный язык, который может запускать файлы сценариев оболочки. |
сплит.ш | Файл, содержащий весь код для разделения файла |
-file, -file = Book.csv | Имя файла, которое необходимо разделить |
-длина, -длина = 30 | Разделить файл по длине |
-размер, -размер = 10 КБ | Разделить файл по размеру |
- без жатки | Не включать заголовок в каждый файл |
- путь выхода | Установить путь к файлу разделения |
- Идентификатор используется для определения используемого метода разделения - это может быть выполнено по длине (-length) или по размеру (-size), где SIZE - это не более SIZE байтов строк на выходной файл.
- РАЗМЕР может быть одним из следующих или целым числом, за которым может следовать один из следующих множителей
суффикс | множитель |
---|---|
КБ | 1000 |
К | 1024 |
МБ | 1000 x 1000 |
M | 1024 x 1024 |
. .. и так далее для G (гигабайты), T (терабайты), P (петабайты), E (эксабайты), Z (зеттабайты), Y (йоттабайты).
Вывод: Формат разбиения файла:
Разделение_год_месяц_деньЧетре_минуты_вековой_нумерации
Пример:
- Разделить по длине:
Ввод:
bash split.sh -file = EmployeeTable.csv --output-path = / Users / poojafartyal / Documents / NodeJS \ Training / Bash-split / Out / -length = 100
Выход: каждый выходной файл содержит 100 записей с заголовком
Например: EmployeeTable_split_2020_05_07T10_03_13_00.csv,
EmployeeTable_split_2020_05_07T10_03_13_01.csv
Разделить по размеру:
Ввод:
bash split.sh -file = EmployeeTable.csv -size = 10KB –without-header
Вывод: размер каждого разбитого файла составляет 10 КБ и без заголовка.
Например: EmployeeTable_split_2020_05_07T10_03_13_00.csv, EmployeeTable_split_2020_05_07T10_03_13_01.