问题
Suppose I have a Unix shell variable as below
variable=abc,def,ghij
I want to extract all the values (abc
, def
and ghij
) using a for loop and pass each value into a procedure.
The script should allow extracting arbitrary number of comma-separated values from $variable
.
回答1:
You can use the following script to dynamically traverse through your variable, no matter how many fields it has as long as it is only comma separated.
variable=abc,def,ghij
for i in $(echo $variable | sed "s/,/ /g")
do
# call your procedure/other scripts here below
echo "$i"
done
Instead of the echo "$i"
call above, between the do
and done
inside the for loop, you can invoke your procedure proc "$i"
.
Update: The above snippet works if the value of variable does not contain spaces. If you have such a requirement, please use one of the solutions that can change IFS
and then parse your variable.
Hope this helps.
回答2:
Not messing with IFS
Not calling external command
variable=abc,def,ghij
for i in ${variable//,/ }
do
# call your procedure/other scripts here below
echo "$i"
done
Using bash string manipulation http://www.tldp.org/LDP/abs/html/string-manipulation.html
回答3:
If you set a different field separator, you can directly use a for
loop:
IFS=","
for v in $variable
do
# things with "$v" ...
done
You can also store the values in an array and then loop through it as indicated in How do I split a string on a delimiter in Bash?:
IFS=, read -ra values <<< "$variable"
for v in "${values[@]}"
do
# things with "$v"
done
Test
$ variable="abc,def,ghij"
$ IFS=","
$ for v in $variable
> do
> echo "var is $v"
> done
var is abc
var is def
var is ghij
You can find a broader approach in this solution to How to iterate through a comma-separated list and execute a command for each entry.
Examples on the second approach:
$ IFS=, read -ra vals <<< "abc,def,ghij"
$ printf "%s\n" "${vals[@]}"
abc
def
ghij
$ for v in "${vals[@]}"; do echo "$v --"; done
abc --
def --
ghij --
回答4:
#/bin/bash
TESTSTR="abc,def,ghij"
for i in $(echo $TESTSTR | tr ',' '\n')
do
echo $i
done
I prefer to use tr instead of sed, becouse sed have problems with special chars like \r \n in some cases.
other solution is to set IFS to certain separator
回答5:
Try this one.
#/bin/bash
testpid="abc,def,ghij"
count=`echo $testpid | grep -o ',' | wc -l` # this is not a good way
count=`expr $count + 1`
while [ $count -gt 0 ] ; do
echo $testpid | cut -d ',' -f $i
count=`expr $count - 1 `
done
回答6:
Another solution not using IFS and still preserving the spaces:
$ var="a bc,def,ghij"
$ while read line; do echo line="$line"; done < <(echo "$var" | tr ',' '\n')
line=a bc
line=def
line=ghij
回答7:
Here is an alternative tr based solution that doesn't use echo, expressed as a one-liner.
for v in $(tr ',' '\n' <<< "$var") ; do something_with "$v" ; done
It feels tidier without echo but that is just my personal preference.
回答8:
Here's my pure bash solution that doesn't change IFS, and can take in a custom regex delimiter.
loop_custom_delimited() {
local item
for item in $(echo $2 | sed 's/ /'`echo -e "\010"`'/g' | sed -E "s/$1/ /g"); do
item=$(echo $item | sed 's/'`echo -e "\010"`'/ /g')
eval "${3:-"$item"}"
done
}
loop_custom_delimited ',' "a,b 1,b 2" 'echo $item'
echo ""
loop_custom_delimited ',' 'echo a,echo b 1,echo "b 2"'
echo ""
loop_custom_delimited ':([0-9]+)?(\.?[0-9]+):' "a:12.34:b 1:.1:b 2" 'echo "$item"'
echo ""
loop_custom_delimited ':([0-9]+)?(\.?[0-9]+):' 'echo a:1.3:echo b 1:4:echo b 2'
来源:https://stackoverflow.com/questions/27702452/loop-through-a-comma-separated-shell-variable