循环逗号分隔的shell变量

时间:2014-12-30 09:07:59

标签: shell loops unix for-loop cut

假设我有一个Unix shell变量,如下所示

variable=abc,def,ghij

我想使用for循环提取所有值(abcdefghij)并将每个值传递给过程。

该脚本应允许从$variable中提取任意数量的逗号分隔值。

9 个答案:

答案 0 :(得分:96)

没有弄乱IFS
不调用外部命令

variable=abc,def,ghij
for i in ${variable//,/ }
do
    # call your procedure/other scripts here below
    echo "$i"
done

使用bash字符串操作http://www.tldp.org/LDP/abs/html/string-manipulation.html

答案 1 :(得分:76)

只要逗号分隔,您可以使用以下脚本动态遍历变量,无论它有多少个字段。

variable=abc,def,ghij
for i in $(echo $variable | sed "s/,/ /g")
do
    # call your procedure/other scripts here below
    echo "$i"
done

您可以调用过程echo "$i",而不是上面的do调用,在{for循环中doneproc "$i"之间调用。


更新:如果变量的值不包含空格,则上述代码段有效。如果您有这样的要求,请使用其中一个可以更改IFS然后解析变量的解决方案。


希望这有帮助。

答案 2 :(得分:39)

如果您设置了不同的字段分隔符,则可以直接使用for循环:

IFS=","
for v in $variable
do
   # things with "$v" ...
done

您还可以将值存储在数组中,然后按照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

测试

$ variable="abc,def,ghij"
$ IFS=","
$ for v in $variable
> do
> echo "var is $v"
> done
var is abc
var is def
var is ghij

您可以在How to iterate through a comma-separated list and execute a command for each entry的此解决方案中找到更广泛的方法。

第二种方法的例子:

$ 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 --

答案 3 :(得分:4)

#/bin/bash   
TESTSTR="abc,def,ghij"

for i in $(echo $TESTSTR | tr ',' '\n')
do
echo $i
done

我更喜欢使用tr而不是sed,因为在某些情况下,像\ r \ n之类的特殊字符有问题。

其他解决方案是将IFS设置为某个分隔符

答案 4 :(得分:0)

试试这个。

#/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

答案 5 :(得分:0)

另一种不使用IFS且仍保留空格的解决方案:

$ var="a bc,def,ghij"
$ while read line; do echo line="$line"; done < <(echo "$var" | tr ',' '\n')
line=a bc
line=def
line=ghij

答案 6 :(得分:0)

这是基于tr的替代解决方案,它不使用回声(表示为单线)。

for v in $(tr ',' '\n' <<< "$var") ; do something_with "$v" ; done

感觉没有回声,但那只是我个人的喜好。

答案 7 :(得分:0)

这是我的纯bash解决方案,它不会更改IFS,并且可以采用自定义的正则表达式定界符。

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'

答案 8 :(得分:0)

以下解决方案:

  • 不需要惹IFS
  • 不需要辅助变量(例如 i 循环中的 for
  • 应该很容易扩展以适用于多个分隔符(在模式中使用像 [:,] 这样的括号表达式)
  • 真的只在指定的分隔符上拆分,而不是 - 就像这里介绍的其他一些解决方案一样,例如空格也是。
  • 与 POSIX 兼容
  • 不会遇到在 bash 的 nocasematch 打开时可能出现的任何细微问题,并且在匹配中使用具有小写/大写版本的分隔符,例如 ${parameter/pattern/string} 或 {{1} }

注意:

  • 但是它确实对变量本身起作用并从中弹出每个元素 - 如果不需要,则需要一个辅助变量
  • 它假定 case 已设置,如果未设置且 var 有效,则会失败
set -u

请注意,需要相应地引用模式中特殊字符的分隔符(例如文字 while true; do x="${var%%,*}" echo $x #x is not really needed here, one can of course directly use "${var%%:*}" if [ -z "${var##*,*}" ] && [ -n "${var}" ]; then var="${var#*,}" else break fi done )。