Bash. Split text to array by delimiter [duplicate] - arrays

This question already has answers here:
How to split a string into an array in Bash?
(24 answers)
Closed 1 year ago.
Can somebody help me out. I want to split TEXT(variable with \n) into array in bash.
Ok, I have some text-variable:
variable='13423exa*lkco3nr*sw
kjenve*kejnv'
I want to split it in array.
If variable did not have new line in it, I will do it by:
IFS='*' read -a array <<< "$variable"
I assumed the third element should be:
echo "${array[2]}"
>sw
>kjenve
But with new line it is not working. Please give me right direction.

Use readarray.
$ variable='13423exa*lkco3nr*sw
kjenve*kejnv'
$ readarray -d '*' -t arr < <(printf "%s" "$variable")
$ declare -p arr
declare -a arr=([0]="13423exa" [1]="lkco3nr" [2]=$'sw\nkjenve' [3]="kejnv")
mapfile: -d: invavlid option
Update bash, then use readarray.
If not, replace separator with zero byte and read it element by element with read -d ''.
arr=()
while IFS= read -d '' -r e || [[ -n "$e" ]]; do
arr+=("$e")
done < <(printf "%s" "$variable" | tr '*' '\0');
declare -p arr
declare -a arr=([0]="13423exa" [1]="lkco3nr" [2]=$'sw\nkjenve' [3]="kejnv")

You can use the readarray command and use it like in the following example:
readarray -d ':' -t my_array <<< "a:b:c:d:"
for (( i = 0; i < ${#my_array[*]}; i++ )); do
echo "${my_array[i]}"
done
Where the -d parameter defines the delimiter and -t ask to remove last delimiter.

Use a ending character different than new line
end=.
read -a array -d "$end" <<< "$v$end"
Of course this solution suppose there is at least one charecter not used in your input variable.

Related

How to parse and convert string list to JSON string array in shell command?

How to parse and convert string list to JSON string array in shell command?
'["test1","test2","test3"]'
to
test1
test2
test3
I tried like below:
string=$1
array=${string#"["}
array=${array%"]"}
IFS=',' read -a array <<< $array;
echo "${array[#]}"
Any other optimized way?
As bash and jq are tagged, this solution relies on both (without summoning eval). The input string is expected to be in $string, the output array is generated into ${array[#]}. It is robust wrt spaces, newlines, quotes, etc. as it uses NUL as delimiter.
mapfile -d '' array < <(jq -j '.[] + "\u0000"' <<< "$string")
Testing
string='["has spaces\tand tabs","has a\nnewline","has \"quotes\""]'
mapfile -d '' array < <(jq -j '.[] + "\u0000"' <<< "$string")
printf '==>%s<==\n' "${array[#]}"
==>has spaces and tabs<==
==>has a
newline<==
==>has "quotes"<==
eval "array=($( jq -r 'map( #sh ) | join(" ")' <<<"$json" ))"

Getting the output of a cat command into an array

How can I get just the filenames into an array using the cat command?
How I've been trying:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(cat /proc/swaps | grep "swap")
This either grabs all the information from the output into an array, or just doesn't work. How can I successfully get my expected output of [/swapfile, /dev/hda1, /some/other/swap] into an array form using the cat command?
readarray array < <(awk '/swap/{print $1}' /proc/swaps)
Bash introduced readarray in version 4 which can take the place of the while read loop. readarray is the solution you want.
here is the syntax
readarray variable < inputfile
echo "${variable[0]}" ' to print the first element in array

Return awk split array to a bash variable

I have a requirement to split a string on a multi-character delimiter and return the values into an array in Bash for further processing
IFS can take a single character delimiter.
a="2;AAAAA;BBBBB;1111_MultiCharDel_2;CCCC;DDDDDD;22222_MultiCharDel_2;EEEE;FFFFFFF;22222"
awk'{split($0,ArrayDeltaMulDep,"_MultiCharDel_")}' <<< $a
The input string can have several substrings separated by the MultiCharDel delimiter.
How can i access this array ArrayDeltaMulDep fur further processing in Bash?
Your example string, a, does not contain newlines. If that is true in general, then:
a="2;AAAAA;BBBBB;1111_MultiCharDel_2;CCCC;DDDDDD;22222"
readarray -t b <<< "${a//MultiCharDel/$'\n'}"
We can verify that this split the string properly using declare -p to show the value of b:
$ declare -p b
declare -a b=([0]="2;AAAAA;BBBBB;1111_" [1]="_2;CCCC;DDDDDD;22222")
How it works:
readarray -t b
This reads lines from stdin and puts then in a bash array b.
<<< "${a//MultiCharDel/$'\n'}"
${a//MultiCharDel/$'\n'} uses pattern substitution to replace MultiCharDel with a newline character. <<< provides the result as stdin to the command readarray.
Hat tip: Chepner
More general solution
A bash string will never contain a null character (hex 00). Using GNU sed:
b=()
while read -d '' -r line
do
b+=("$line")
done < <(sed 's/MultiCharDel/\x00/g; s/$/\x00/' <<<"$a")
This again creates an array with the desired splitting:
$ declare -p b
declare -a b=([0]="2;AAAAA;BBBBB;1111_" [1]="_2;CCCC;DDDDDD;22222")

put input with spaces as a single element in array in bash

I have a file from which I extract the first three columns using the cut command and write them into an array.
When I check the length of the array , it is giving me four. I need the array to have only 3 elements.
I think it's taking space as the delimiter for array elements.
aaa|111|ADAM|1222|aauu
aaa|222|MIKE ALLEN|5678|gggg
aaa|333|JOE|1222|eeeee
target=($(cut -d '|' -f1-3 sample_file2.txt| sort -u ))
In bash 4 or later, use readarray with process substitution to populate the array. As is, your code cannot distinguish between the whitespace separating each line in the output from the whitespace occurring in "Mike Allen". The readarray command puts each line of the input into a separate array element.
readarray -t target < <(cut -d '|' -f1-3 sample_file2.txt| sort -u)
Prior to bash 4, you need a loop to read each line individually to assign to the array.
while IFS='' read -r line; do
target+=("$line")
done < <(cut -d '|' -f1-3 sample_file2.txt | sort -u)
This should work:
IFS=$'\n' target=($(cut -d '|' -f1-3 sample_file2.txt| sort -u ))
Example:
#!/bin/bash
IFS=$'\n' target=($(cut -d '|' -f1-3 sample_file2.txt| sort -u ))
echo ${#target[#]}
echo "${target[1]}"
Output:
3
aaa|222|MIKE ALLEN
As an alternative, using the infamous eval,
eval target=($(cut -sd '|' -f1-3 sample_file2.txt | sort -u | \
xargs -d\\n printf "'%s'\n"))

How to split a multi-line string containing the characters "\n" into an array of strings in bash? [duplicate]

This question already has answers here:
How do I split a string on a delimiter in Bash?
(37 answers)
Closed 6 years ago.
I have a string in the following format:
I'm\nNed\nNederlander
I'm\nLucky\nDay
I'm\nDusty\nBottoms
I would like to move this to an array of strings line by line such that:
$ echo "${ARRAY[0]}"
I'm\nNed\nNederlander
$ echo "${ARRAY[1]}"
I'm\nLucky\nDay
$ echo "${ARRAY[2]}"
I'm\nDusty\nBottoms
However, I'm running into problems with the "\n" characters within the string itself. They are represented in the string as two separate characters, the backslash and the 'n', but when I try to do the array split they get interpreted as newlines. Thus typical string splitting with IFS does not work.
For example:
$ read -a ARRAY <<< "$STRING"
$ echo "${#ARRAY[#]}" # print number of elements
2
$ echo "${ARRAY[0]}"
I'mnNednNederla
$ echo "${ARRAY[1]}"
der
By default, the read builtin allows \ to escape characters. To turn off this behavior, use the -r option. It is not often you will find a case where you do not want to use -r.
string="I'm\nNed\nNederlander
I'm\nLucky\nDay
I'm\nDusty\nBottoms"
arr=()
while read -r line; do
arr+=("$line")
done <<< "$string"
In order to do this in one-line (like you were attempting with read -a), actually requires mapfile in bash v4 or higher:
mapfile -t arr <<< "$string"
mapfile is more elegant, but it is possible to do this in one (ugly) line with read (useful if you're using a version of bash older than 4):
IFS=$'\n' read -d '' -r -a arr <<< "$string"

Resources