循环通过逗号分隔的 shell 变量
Posted
技术标签:
【中文标题】循环通过逗号分隔的 shell 变量【英文标题】:Loop through a comma-separated shell variable 【发布时间】:2015-02-26 10:35:13 【问题描述】:假设我有一个如下的 Unix shell 变量
variable=abc,def,ghij
我想使用 for 循环提取所有值(abc
、def
和 ghij
)并将每个值传递给一个过程。
脚本应该允许从$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 循环内的do
和done
之间,您可以调用您的过程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/string
或 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
请注意,作为模式中特殊字符的分隔符(例如文字 *
)需要相应地引用。
【讨论】:
【参考方案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中提取值