请教各位老师1个shell 问题,为什么我在while循环中,对变量进行了相加,但是循环结束后,这个变量还是0,我猜是因为管道|的问题,但是不知道怎么避免这个问题
[tidb@tidb01 tmp]$ cat test.sh
count=0
df -PT|while read line
do
echo $line
count=expr $count + 1
done
echo $count
#还是0
请教各位老师1个shell 问题,为什么我在while循环中,对变量进行了相加,但是循环结束后,这个变量还是0,我猜是因为管道|的问题,但是不知道怎么避免这个问题
[tidb@tidb01 tmp]$ cat test.sh
count=0
df -PT|while read line
do
echo $line
count=expr $count + 1
done
echo $count
#还是0
你是要读取df -PT结果的行数?df -PT |wc -l 这样就行了
写这段shell想计算行数?还是某列的count?
count=0
df -PT | while read line
do
echo $line
((count++))
done
echo $count
count=df -PT|wc -l
就行,用管道符进子shell了,改变不了父shell的变量。
#!/bin/bash
declare -x count=0
while IFS= read -r line
do
echo $line
count=$(expr $count + 1)
done <<< “$(df -PT)”
echo “Count: $count”
你没说自己用的是什么 shell, 但是在大部分的 shell 里, 管道的命令经常是在 subshell 里执行的,在 subshell 里对变量做的更改,是没办法在 subshell 外部获取的。
不同的 shell 表现不一样,BASH 是这样的:仅当 loop 是管道的最后一部分,才会创建一个 subshell (也就是你写的脚本的场景)
解决思路是去掉管道。以 BASH 为例:
把 df -PT
的输出写到一个临时文件,把临时文件的内容用 <
重定向一下
把 df -PT
以外的处理都放一起
df -PT |
{
while read line
do
linecount=$((linecount + 1))
done
echo "$linecount"
}
while read line
do
linecount=$((linecount + 1))
done < <(df -PT)
echo "$linecount"
while read line
do
linecount=$((linecount + 1))
done <<< $(df -PT)
echo "$linecount"
mkfifo p
df -PT > p &
while read line
do
linecount=$((linecount + 1))
done < p
echo "$linecount"
不止上面这些,肯定还有不少方法可以绕过
这种方式也不行的,while 循环结束后,count的值还是0
我的需求是,循环df -PT 里面的每一行,做判断,如果文件系统满足某1个条件就+1,但是这样直接把df -PT当成1个整体,并没有循环,没有达到效果
我的需求是,循环df -PT 里面的每一行,做判断,如果文件系统满足某1个条件就+1,并不是直接统计df -PT 有多少行
感谢大佬
df -PT |
{
while read line
do
linecount=$((linecount + 1))
done
echo “$linecount”
}
这种办法是OK的
但是下面就不行了
while read line
do
linecount=$((linecount + 1))
done <<< $(df -PT)
echo “$linecount”
应为把$(df -PT) 当成了1整行,并没有进行循环,所以结果是1
df -PT|awk ‘{if ($4>0) {print$4}}’|wc -l
这个意思?
你用的是 bash 吧?
可以在命令行这样测一下 HereString 的表现,应该不会是1行的
cat <<< $(df)
首先管道属于非内建指令,linux执行shell时,会创建“子shell”运行shell中的命令,当运行到非内建指令时,会创建“shell”运行非内建指令,变量的作用于在每个shell中有效,所以,非内建指令中定义的这些变量就只能在shell运行,而在子shell中不生效,所以,即便在while中给count赋值了,子shell中也不会获取到这个值。这类属于shell变量作用域问题,与其他语言不同。
解决这个问题的办法有两种
如果不是必须使用管道符的方式写while循环,可以用重定向的写法,这种写法循环内的变量在子shell中是生效的,比较简便
如果非要使用管道符的方式,可以创建临时文件,用于存放shell中的输出。
感谢老师的回复
[root@tidb01 ~]# cat <<< $(df)
Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/rhel-root 49250820 23256508 25994312 48% / devtmpfs 2150452 0 2150452 0% /dev tmpfs 2162688 0 2162688 0% /dev/shm tmpfs 2162688 11996 2150692 1% /run tmpfs 2162688 0 2162688 0% /sys/fs/cgroup /dev/sda1 1038336 132920 905416 13% /boot /dev/mapper/datavg-lv_deploy 30832548 796296 28447004 3% /tidb-deploy /dev/mapper/datavg-lv_data 51474912 1377720 47459368 3% /tidb-data tmpfs 432540 0 432540 0% /run/user/0
不知道你的环境和版本,应该是 IFS
的配置问题。
为了让 shell 正确识别到特殊符号 \n
, 你可以加上双引号。
cat <<< "$(df)"
可以了,谢谢大佬,谢谢老师
此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。