Bash string to array with spaces and extra delimiters

I am trying to create arrays from strings that have a separator ("|") as separators and include spaces. For a while I looked around, and thanks to sources such as How do I split a line on a delimiter in Bash? , Splitting a string into an array and a bunch more. I'm close, but it doesn’t quite work. The two main problems are that there are spaces in the lines, there are start and end separators, and some fields are blank. Also, instead of just displaying the values, I need to assign them to the variables. Here is the source data format:

|username|full name|phone1|phone2|date added|servers|comments| 

Example:

 |jdoe | John Doe| 555-1212 | |1/1/11 | workstation1, server1 | added by me | 

This is what I need:

 Username: jdoe Fullname: John Doe Phone1: 555-1212 Phone2: Date_added: 1/1/11 Servers: workstation1, server1 Comments: guest account 

Change: I use sed to remove the first and last separator and spaces before and after each separator, now input:

 jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me 

Here is what I tried:

 oIFS="$IFS"; IFS='|' for line in 'cat $userList'; do arr=("$line") echo "Username: ${arr[0]}" #not assigning a variable, just testing the output echo "Full Name: ${arr[1]}" echo "Phone 1: ${arr[2]}" echo "Phone 2: ${arr[3]}" # etc.. done IFS="$oIFS" 

Output:

 Username: Full Name: Phone 1: Phone 2: Username: jdoe Full Name: Phone 1: Phone 2: Username: John Doe Full Name: Phone 1: Phone 2: 

One more thing I tried:

 for line in 'cat $userList'; do arr=(${line//|/ }) echo "Username: ${arr[0]}" echo "Full Name: ${arr[1]}" echo "Phone 1: ${arr[2]}" echo "Phone 2: ${arr[3]}" # etc done 

Output:

 Username: jdoe Full Name: John Phone 1: Phone 2: Username: Doe Full Name: 555-1212 Phone 1: Phone 2: 

Do you have some ideas? Thanks!!

+5
source share
4 answers

Your first attempt is pretty close. Main problems:

  • for line in `cat $userList` splits the file into $IFS , not line breaks. Therefore, before the loop, you must set IFS=$'\n' and IFS='|' inside the loop. (By the way, it is worth noting that the for ... in `cat ...` approach reads the entire file and then splits it, so this is not the best approach if the file can be large. A read based approach would be better in this case.)
  • arr=("$line") , wrapping $line in double quotes, prevents word splitting and therefore makes $IFS unnecessary. It should just be arr=($line) .
  • Since $line has a leading channel, you need to remove it before you go to arr=($line) (by writing something like $line="${line#|}" ), otherwise you need to treat arr as 1 -based array (since ${arr[0]} , the part before the first channel will be empty).

Combining this, you will get something like this:

 oIFS="$IFS" IFS=$'\n' for line in `cat $userList`; do IFS='|' arr=($line) echo "Username: ${arr[1]}" #not assigning a variable, just testing the output echo "Full Name: ${arr[2]}" echo "Phone 1: ${arr[3]}" echo "Phone 2: ${arr[4]}" # etc.. done IFS="$oIFS" 

(Note. I was not worried about the top and bottom spaces of the fields, because of the “I can take this step separately” part ... or did I misunderstand this? Do you need help with this part?)

+9
source
 IFS='|' while read username fullname phone1 phone2 dateadded servers comments; do printf 'username: %s\n' "$username" printf 'fullname: %s\n' "$fullname" printf 'phone1: %s\n' "$phone1" printf 'phone2: %s\n' "$phone2" printf 'date added: %s\n' "$dateadded" printf 'servers: %s\n' "$servers" printf 'comments: %s\n' "$comments" done < infile.txt 
+2
source

Another solution:

 shopt -s extglob infile='user.lst' declare -a label=( "" "Username" "Full Name" "Phone 1" "Phone 2" ) while IFS='|' read -a fld ; do for (( n=1; n<${#label[@]}; n+=1 )); do item=${fld[n]} item=${item##+([[:space:]])} echo "${label[n]}: ${item%%+([[:space:]])}" done done < "$infile" 

Leading and trailing spaces will be deleted.

+1
source

Using arrays and paste . Does not account for empty fields, as the OP says this is not a requirement.

 userList='jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me' fields=("Username: " "Full Name: " "Phone 1: " "Phone 2: " "Date_added: " "Servers: " "Comments: ") IFS='|' read -ra data <<<${userList} paste <(IFS=$'\n'; echo "${fields[*]}") <(IFS=$'\n'; echo "${data[*]}") Username: jdoe Full Name: John Doe Phone 1: 555-1212 Phone 2: Date_added: 1/1/11 Servers: workstation1, server1 Comments: added by me 
0
source

Source: https://habr.com/ru/post/1388650/


All Articles