在bash中使用for循环嵌套while循环

时间:2019-02-19 15:53:27

标签: bash loops

说明

你好

我试图遍历某些命令并将其输出保存到文件中,并在遍历这些命令时,还要检查保存了其输出的文件,以便我们可以在文件中循环比较命令时将它们与文件进行比较同时。最后,检查循环命令的输出是否与该文件中先前保存的输出匹配。 (还要检查文件是否不包含输出并将其添加到文件中,以便我们以后可以再次使用它进行比较)

这是我的主要脚本,它遍历/usr/local/bin/内部的上述命令,因此我可以直接从shell运行它们。

#!/bin/bash
wallets=`find /usr/local/bin/ -iname '*-cli'`

for i in $wallets; do
    current_blocks=`$I getblockcount`
    coin_name=${i:15:-4} # I use `:15:-4` here to cut the path and the last 4 characters. (For example it's `/usr/local/bin/bitcoin-cli` so I change it to `bitcoin` only
    echo $coin_name $current_blocks
    echo $coin_name $current_blocks >> blocks.log
done

回声恰恰为我们提供了这个条件(假设$wallets中有2个项目;

bitcoin 1457824
litecoin 759345

这是while循环,我大概会用它来读取文件;

while read line ; do
    set $line
    echo $1 $2
done < blocks.log

运行时还会提供给我们该输出;

bitcoin 1457824
litecoin 759345

因此,由于我具有这两个代码位,因此现在我想将它们合并为一个脚本,以便既可以使用第一个代码位循环命令,也可以将它们与blocks.log文件进行比较。 (同样,还要检查文件是否不包含输出并将其添加到文件中,以便我们以后可以再次使用它进行比较)

我的第一个(也是失败的)方法;

for i in $wallets; do

    current_blocks=`$i getblockcount`
    coin_name=${i:15:-4}

    while read line; do
        set $line
        if [ "$1" == "$coin_name" ]; then
            echo "File contains the coin_name, compare the blocks now"
            if (( "$current_blocks" >= "$2" )); then
                echo "Current blocks are greater than the saved blocks"
                echo "Saving the new blocks count now"
                sed -i "s/$1/$1 $current_blocks/" blocks.log
            else
                echo "Current blocks are less than or equals to saved blocks"
            fi
        else
            echo "File does not contain the coin_name, adding it now"
            echo "$coin_name $current_blocks" >> blocks.log
        fi
    done < blocks.log

done

我第二次(另一次失败)尝试;

for i in $wallets; do

    current_blocks=`$i getblockcount`
    coin_name=${i:15:-4}

    read line < blocks.log
    set $line
    if [ "$1" == "$coin_name" ]; then
        echo "File contains the coin_name, compare the blocks now"
        if (( "$current_blocks" >= "$2" )); then
            echo "Current blocks are greater than the saved blocks"
            echo "Saving the new blocks count now"
            # sed -i "s/$1/$1 $current_blocks/" blocks.log
        else
            echo "Current blocks are less than or equals to saved blocks"
        fi
    else
        echo "File does not contain the coin_name, adding it now"
        echo "$coin_name $current_blocks" >> blocks.log
    fi

done

我在做什么错了?

1 个答案:

答案 0 :(得分:1)

  

我在做什么错了?

在第二次尝试中,您正确地认识到该问题并不要求嵌套循环,但read line < blocks.log仍然是错误的,因为它仅重复读取第一行。这是经过更正的版本,带有以下注释:

line='' # no line read yet
for i in $wallets; do
    current_blocks=`$i getblockcount`
    coin_name=`basename $i -cli`    # I just prefer it more readable.
    if [ ! "$line" ]; then          # we need to read a line from log
        read line
        set -- $line
    fi
    if [ "$1" == "$coin_name" ]; then
        line='' # read new line next time
        echo "File contains the coin_name, compare the blocks now"
        if (( current_blocks > $2 )); then
            echo "Current blocks are greater than the saved blocks"
            echo "Saving the new blocks count now"
            sed -i "/$1/c$1 $current_blocks" blocks.log
        else
            echo "Current blocks are less than or equal to saved blocks"
        fi
    else
        # $line as well as $1 and $2 remain set, will be used in next loop cycle
        echo "File does not contain the coin_name, adding it now"
        if [ ! "$1" ]; then         # $1 is empty at EOF
            # create a new blocks.log to not disturb reading from original:
            cp blocks.log $$; mv $$ blocks.log
            echo "$coin_name $current_blocks" >>blocks.log
        else
            # insert before current line (address /$1/)
            sed -i "/$1/i$coin_name $current_blocks" blocks.log
        fi
    fi
done <blocks.log

通常,我们从日志中按顺序为每个钱包读取一行,因此我们有一个for i in $wallets循环,其中有一个read line。但是有一种情况是,自上一个脚本运行以来,已累积了一个新的钱包,该钱包不在文件中。在这里,我们已经从日志文件中读取了下一个钱包行,因此我们将该行数据保存到下一个循环周期,然后不再读取新行。

另一个重要的一点是,在循环运行时,我们切勿修改blocks.log input 文件-这会将新数据添加到旧数据中,并混合了绵羊和山羊。幸运的是,sed -i创建了一个新的blocks.log output 文件,而旧的 input 文件仍然是匿名且不受干扰的。只有当我们echo … >>blocks.log时,我们自己才必须确保创建新的blocks.log

请注意,这种方法要求对钱包进行分类;由于您的-cli文件都位于目录/usr/local/bin/中,因此可以写wallets=/usr/local/bin/*-cli而不是find行。

相关问题