I'm trying to create arrays from strings that have pipe ("|") as delimiters and include spaces. I've been looking around for a while and I've gotten close thanks to sources like How do I split a string on a delimiter in Bash?, Splitting string into array and a bunch more. I'm close but it's not quite working. The two main problems are that there are spaces in the strings, there are starting and ending delimiters, and some of the fields are blank. Also, instead of just echoing the values, I need to assign them to variables. Here's the format of the source data:
|username|full name|phone1|phone2|date added|servers|comments|
Example:
|jdoe | John Doe| 555-1212 | |1/1/11 | workstation1, server1 | added by me |
Here's what I need:
Username: jdoe
Fullname: John Doe
Phone1: 555-1212
Phone2:
Date_added: 1/1/11
Servers: workstation1, server1
Comments: guest account
Edit: I use sed to strip out the first and last delimiter and spaces before and after each delimiter, input is now:
jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me
Here's things I've 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:
Another 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:
Any suggestions? Thanks!!
Instead of the read command, the tr command is used to split the string on the delimiter. The problem with this approach is that the array element are divided on ‘space delimiter’. Because of that, elements like ‘Linux Mint’ will be treated as two words. Here’s the output of the above script:
In this quick tip, you'll learn to split a string into an array in Bash script. Let’s say you have a long string with several words separated by a comma or underscore. You want to split this string and extract the individual words. You can split strings in bash using the Internal Field Separator (IFS) and read command or you can use the tr command.
Declaring an array in Bash is easy, but pay attention to the syntax. If you are used to programming in other languages, the code might look familiar, but there are subtle differences that are easy to miss. To declare your array, follow these steps: Follow that variable name with an equal sign. The equal sign should not have any spaces around it
The option -a with read command stores the word read into an array in bash. In simpler words, the long string is split into several words separated by the delimiter and these words are stored in an array.
Your first attempt is pretty close. The main problems are these:
for line in `cat $userList`
splits the file by $IFS
, not by line-breaks. So you should set IFS=$'\n'
before the loop, and IFS='|'
inside the loop. (By the way, it's worth noting that the for ... in `cat ...`
approach reads out the entire file and then splits it up, so this isn't the best approach if the file can be big. A read
-based approach would be better in that case.)arr=("$line")
, by wrapping $line
in double-quotes, prevents word-splitting, and therefore renders $IFS
irrelevant. It should just be arr=($line)
.$line
has a leading pipe, you either need to strip it off before you get to arr=($line)
(by writing something like $line="${line#|}"
), or else you need to treat arr
as a 1-based array (since ${arr[0]}
, the part before the first pipe, will be empty).Putting it together, you 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 didn't worry about the fields' leading and trailing spaces, because of the "I can do that step separately" part . . . or did I misunderstand that? Do you need help with that part as well?)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With