将分隔输出读入多个Bash变量

5

这应该很简单,我之前在某个脚本中做过这件事,但我找不到我的示例(或相当的示例),今天这个问题让我快要疯了。(即使我没有包含脚本的其余部分,这也是用于脚本内部使用,而不是交互式的。)

cat testfile | grep -e eth0

返回:

eth0         123.45.67.8/23                  u/u  Internet - Cable WAN

最终结果是我需要为每个元素设置变量。即,就像我手动完成的那样:
INTF = "etho"
IPADDR = "123.45.67.8/23"
STS = "u/u"
DESC = "Internet - Cable WAN"

我认为我可以做类似于这样的事情:

cat testfile | grep -e eth0 | awk '{print $2}' | xargs read IPADDR

或者
cat testfile | grep -e eth0 | cut -d " " -n2 | read IPADDR

但是我尝试过的所有方法都没有带来快乐......我的路障是什么(头疼)?

编辑以补充-脚本比仅抓取一个IP更为复杂,因此我的示例会导致人们得出这样的结论。它是基于cron的脚本,每分钟运行一次,它通过8个接口运行循环,并在特定的警报条件下发送消息。当我使用硬编码变量运行其余部分的脚本时,它能正常工作,我只是被问到了让我困惑的部分。


2
为什么不直接使用 IPADDR=$(cat outputfile | grep -e eth0 | awk '{print $2}') - Néstor Lucas Martínez
1
顺便提一下,在你描述问题时,第一个例子中使用了“outputfile”作为文件名,而在第二个例子中使用了“testfile”。要小心处理。 - Néstor Lucas Martínez
@NéstorLucasMartínez 这是一种可能性,我没有考虑过这样分配,但我的示例过于简化了,因为这是一个基于cron的脚本,每分钟运行并循环遍历8个接口。(它不仅仅是一个抓取单个IP并运行的脚本。)尽管在那时我实际上不需要设置INTF,但似乎在每个循环中建议执行3次是低效的。 - Tyson
1
然后您可以尝试使用以下命令:read INTF IPADDR STS DESC <<< \cat testfile | grep -e eth0`` - Néstor Lucas Martínez
4个回答

4

如果您想设置4个变量,而不是执行4次cut,您可以像这样使用read

#!/bin/bash
#
read INTF IPADDR STS DESC <<< $(cat testfile | grep -e eth0)

echo $INTF
echo $IPADDR
echo $STS
echo $DESC

这将在任何空格处“切割”,使用默认的$IFS

如果你想从“aaa,bbb,ccc,ddd”中切割值,你可以在read之前改变IFS值。

例如:

IFS="," read INTF IPADDR STS DESC <<< $(cat testfile | grep -e eth0)

这正是我想做的,用一次读取所有4个。这很有效。Bash不是我的常规环境,子shell总是让我陷入麻烦。 - Tyson

2

如果你想一次性使用read获取所有赋值的变量,可以按照以下方式进行:

read INTF IPADDR STS DESC <<< `cat testfile | grep -e eth0`

0
有很多方法可以做到这一点,你甚至可以扫描你的测试文件,并将结果逐一匹配放入数组中:
#!/bin/bash
file="testfile.txt"

declare -a intf
declare -a ipaddr
declare -a sts
declare -a desc

# - file reader -
while IFS= read -r line; do
    if [[ ${line,,} == *"intf"* ]];then
        intf+=("$(echo $line | cut -d'"' -f2- | cut -d'"' -f1)")
    elif [[ ${line,,} == *"ipaddr"* ]];then
        ipaddr+=("$(echo $line | cut -d'"' -f2- | cut -d'"' -f1)")
    elif [[ ${line,,} == *"sts"* ]];then
        sts+=("$(echo $line | cut -d'"' -f2- | cut -d'"' -f1)")
    elif [[ ${line,,} == *"desc"* ]];then
        desc+=("$(echo $line | cut -d'"' -f2- | cut -d'"' -f1)")
    fi
done < "$file"

if [[ ${#intf[@]} -eq  ${#ipaddr[@]} &&  ${#intf[@]} -eq ${#ipaddr[@]} &&  ${#intf[@]} -eq  ${#sts[@]} ]] ;then
    echo "file read successful! continuing .."
else
    echo "icky, this didn't work"
fi

for ((i=0; i< ${#intf[@]}; i++)) ;do
       echo -e "INTF=${intf[$i]} \nIPADDR=${ipaddr[$i]} \n"

done

输出(类似于):

$ ./script.sh
file read successful! continuing ..
INTF=etho 
IPADDR=123.45.67.8/23 

INTF=etho 
IPADDR=13.45.67.8/23 

INTF=etho 
IPADDR=23.45.67.8/23 

1
在问题中添加了一段说明,更好地解释了需求,而不是仅仅获取单个互联网连接的外部IP。 - Tyson
谢谢,我误读了你的问题,上面是一种在扫描文件后创建数组并检查其一对一关系的方法。 - Mike Q
使用read命令能否更高效地编写desc+=("$(echo $line | cut -d'"' -f2- | cut -d'"' -f1)")等代码,而无需调用子shell? - codeforester
是的,可能没有理由使用echo。 - Mike Q

0

在你的命令中

cat testfile | grep -e eth0 | cut -d " " -n2 | read IPADDR
cat testfile | grep -e eth0 | awk '{print $2}' | xargs read IPADDR

read 命令在子 shell 中运行,因此在主 shell 中不可见。

您需要 进程替换 一次性将值传递到父 shell 中:

read -r intf ipaddr sts desc < <(grep eth0 testfile)

前三个变量将获得grep输出中前三个字段的值(这是基于IFS的字符串拆分),第四个变量desc将获得输出中剩余的标记。


顺带提一下,cat outfile | grep -e eth0UUOC 的一个例子。只需要用 grep eth0 outfile 就可以完成你的工作。


相关:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接