首页 > 解决方案 > sh for 循环的输出搞砸了

问题描述

我目前正在编写一个脚本,它应该检查文件中列出的每个设备的 ATA 安全状态。

使用 Command 检查 ATA 安全状态,该命令smartctl -g security "$drive" | grep -c "ATA Security is:.*NOT FROZEN"输出 0(冻结)或 1(未冻结)并且已经过测试。

该脚本当前如下所示:

# get newline as Seperator
IFS=$(echo)
# get drives
drives=$(cat ./sd-freeze.conf)

# check status for each drive
for drive in $drives
do  
    frozen=$(smartctl -g security "$drive" | grep -c "ATA Security is:.*NOT FROZEN")
    echo "$drive"
    echo "$frozen"
done

sd-freeze.conf 包含以下内容:

/dev/sda
/dev/sdb

输出应该是:

/dev/sda
1
/dev/sdb
1

但不知何故,它是:

/dev/sda
/dev/sdb
0

有谁知道为什么输出顺序混乱(两个设备都没有冻结)?

标签: sh

解决方案


# get newline as Seperator
IFS=$(echo)

$(...)从字符串中删除任何尾随换行符。这条线实际上是设置IFS=''而不是IFS=$'\n'根据需要设置。这意味着$drives下面未引用的内容根本没有被拆分。$drives该循环仅在整个字符串上迭代一次。

一个可能的解决方法是设置IFS=$'\n'在那里换行,但实际上,最好不要IFS全局覆盖。正如睿智的 Raymond Chen所说,“不要使用全局状态来管理本地问题。”

要将一组行读入一个数组,我会使用readarray. 这样脚本的其余部分就不会受到潜在影响。

readarray -t drives < sd-freeze.conf

# check status for each drive
for drive in "${drives[@]}"
do  
    frozen=$(smartctl -g security "$drive" | grep -c "ATA Security is:.*NOT FROZEN")
    echo "$drive"
    echo "$frozen"
done

推荐阅读