循环通过逗号分隔的 shell 变量

Posted

技术标签:

【中文标题】循环通过逗号分隔的 shell 变量【英文标题】:Loop through a comma-separated shell variable 【发布时间】:2015-02-26 10:35:13 【问题描述】:

假设我有一个如下的 Unix shell 变量

variable=abc,def,ghij

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

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

【问题讨论】:

你到底想通过迭代做什么? 我想将每个字段(比如 abc)作为参数传递给过程。 【参考方案1】:

不要搞乱 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

【讨论】:

这样做的好处是您可以使用不同的分隔符嵌套多个循环。好建议! 避免与IFS混淆的好技巧! 小警告 - 如果$i 中的任何值包含空格,它们将被拆分(这可能是它以逗号分隔而不是空格分隔的原因)跨度> 如果之前的函数更改了 IFS 设置,那么这不起作用...更改为:for i in $variable//,/$IFS do; echo "$i"; done 我在尝试这种方法时收到错误消息“替换错误”。【参考方案2】:

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

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" 调用,在for 循环内的dodone 之间,您可以调用您的过程proc "$i"


更新:如果变量的值不包含空格,则上述 sn-p 有效。如果您有这样的需求,请使用可以更改IFS 的解决方案之一,然后解析您的变量。


希望这会有所帮助。

【讨论】:

如果$variable 包含空格,则这不起作用,例如variable=a b,c,d => 打印 4 行 (a | b | c | d) 而不是 3 (a b | c | d) 同时添加了新的引号,例如 ** "value **。如果有任何正则表达式可以删除它,您能否更新一下..【参考方案3】:

如果设置不同的字段分隔符,可以直接使用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 --

【讨论】:

另见***.com/questions/918886/… :-) 祝大家好运。 是的!我也想过,只是它需要以下步骤:while 读入一个数组,另一个循环遍历结果。 当有人真正知道如何使用 shell,而不是把一堆 binutils 放在一起时,这让我很高兴。 你必须将IFS 设置回原来的样子吗? @fedorqui 做到了!这是我想要循环的唯一变量,它使我的 yaml 文件更易于阅读(而不是一个 LONG 环境变量,它有一堆行)【参考方案4】:
#/bin/bash   
TESTSTR="abc,def,ghij"

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

我更喜欢使用 tr 而不是 sed,因为 sed 在某些情况下会遇到特殊字符(如 \r \n)的问题。

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

【讨论】:

【参考方案5】:

我认为在语法上这更干净,并且还通过了 shell-check linting

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

【讨论】:

【参考方案6】:

另一个不使用 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

【讨论】:

这在 bash 中可以正常工作,但是 zsh 会吞下空格。【参考方案7】:

这是一种基于 tr 的替代解决方案,它不使用 echo,表示为单线。

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

没有回声感觉更整洁,但这只是我个人的喜好。

【讨论】:

【参考方案8】:

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

loop_custom_delimited() 
    local list=$1
    local delimiter=$2
    local item
    if [[ $delimiter != ' ' ]]; then
        list=$(echo $list | sed 's/ /'`echo -e "\010"`'/g' | sed -E "s/$delimiter/ /g")
    fi
    for item in $list; do
        item=$(echo $item | sed 's/'`echo -e "\010"`'/ /g')
        echo "$item"
    done

【讨论】:

【参考方案9】:

以下解决方案:

不需要乱搞IFS 不需要辅助变量(如for-loop 中的i) 应该可以轻松扩展以适用于多个分隔符(在模式中使用像 [:,] 这样的括号表达式) 实际上只在指定的分隔符上进行拆分,而不是 - 就像此处介绍的其他一些解决方案一样,例如空格。 与 POSIX 兼容 不会遇到任何微妙的问题,当 bash 的 nocasematch 处于打开状态并且在与 $parameter/pattern/stringcase 的匹配中使用具有小写/大写版本的分隔符时,可能会出现任何微妙的问题

请注意:

但它确实对变量本身起作用并从中弹出每个元素 - 如果不需要,则需要辅助变量 它假定 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

请注意,作为模式中特殊字符的分隔符(例如文字 *)需要相应地引用。

【讨论】:

【参考方案10】:

试试这个。

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

【讨论】:

但是如果我不确定变量 testpid 中的字段数怎么办? 另外,我需要将上述变量的每个字段作为参数传递给过程。我想这样做,直到变量的长度变为零。 (即;所有字段都应传递一次给程序进行处理) 我不知道这个过程。从这个链接你可以得到字段的数量。 http://***.com/questions/8629330/unix-count-of-columns-in-file。之后将 for 循环变为 while 循环。你可以得到那个。 我猜这是从文件中计算字段。如果我需要计算变量中的字段怎么办(假设变量是 testpid=abc,def,ghij) 回显变量并将输出通过管道传输到 awk。否则请参阅我的更新答案。可能有用。

以上是关于循环通过逗号分隔的 shell 变量的主要内容,如果未能解决你的问题,请参考以下文章

如何在“PARTITIONED BY”子句的括号之间以逗号分隔的tick中提取值

在一行上用一个赋值命令给多个变量赋值,各变量之间用啥符号分隔

shell中for循环变量有空格的问题——IFS变量

shell脚本--------for循环

如何从包含逗号分隔条目的变量中创建(不同的)值列表?

shell的for while读取文件写法和区别