どのように動作しますか? forループは変数の結果を削除します。

どのように動作しますか? forループは変数の結果を削除します。

本からbash/kshを学ぶとき。結果を知りたい運動を見つけました。

動作(デバッグ)を理解するために、bash -xを使用してこのスクリプトを実行すると、行変数が数値+ファイル名であることがわかりました。これは、wc -c [ファイル]の結果であるためです。ただし、forループがres変数を設定すると、何らかの形でファイル名が削除され、res = 23
(wc -cの数値結果)のみが表示されます。このようなことが起きているのがわかりますが、その理由をよく理解できませんか?私はforループ構造を理解すると思います。 for i in xxxの機能は何ですか。

練習スクリプトは次のとおりです。

if [ ! $# -eq 2 ] ;then
    echo
    echo "usage: $0 <location> <FileName>"
    echo
    exit 1
fi
TMPFILE=/tmp/count
line=$(find "$1" -name "$2" -type f -print | tee $TMPFILE | wc -l)
aant=$line
nr=0
som=0

while [ $nr -lt "$aant" ] ; do
    nr=$(( nr +1 ))
    bestand=$(head -$nr $TMPFILE | tail -1)
    echo -n "$bestand"
    line=$(wc -c "$bestand")

    for woord in $line ; do
        res=$woord
        break
    done
    echo "  $res"
    som=$(( som + res ))
done

if [ "$aant" -eq 0 ] ; then
    echo "No files found"
else
    echo
    echo "In totaal $aant files take $som bytes of space"
fi

rm $TMPFILE
exit 0

答え1

for word in $line、変数の内容はline次のとおりです。単語に分ける次に、ファイル名グローバル変数を展開します(参照:これら 質問)。その後、ループは各結果値(または「単語」)に対して一度だけ実行されます。ただし、この場合、このbreakステートメントはループの実行を停止するため、ループには最大1回の反復があります。したがって、resループの最初の反復では、set値はそのまま残り、これはスペースで区切られた最初の単語を選択するのと同じ効果がありますline

これを書くより良い方法があります。たとえば、シェル拡張を使用してファイル名を削除できます。これにより、次のものが出力されます23

line='23 somefilename'
res="${line%% *}"
echo "$res"

または、ファイル名をに渡すのではなく、ファイルをwcstdinにリダイレクトしてファイル名を出力しません。wcwc

$ wc -c foo.txt
8 foo.txt
$ wc -c < foo.txt
8

答え2

あなたの質問を正しく理解すると、ここで魔法が起こります。

for woord in $line ; do
    res=$woord
    break
done

これがどのように機能するかを理解するのに役立つように、次のことを考えると便利です。

for N in 1 2 3 4 5; do
    echo $N
done
echo "N is $N"

次に、" break"ステートメントを追加し、次の点を考慮してください。

for N in 1 2 3 4 5; do
    echo $N
    break
done
echo "N is $N"

ループbreakにステートメントを追加することが何であるかを説明できますか?for

私が最初に引用した4行のコードはわずか3行に減らすことができるようです。

for res in $line ; do
    break
done

これは本質的に「不器用な」表現方法です。

res="$(awk '{print $1}' <<< "$line")"

答え3

マニュアルページを確認してくださいwc -c

bytecount filenameスペースで区切られたリストを出力します$line

ループfor $woord in $lineは(最初のスペースまで)から最初の変数を読み取ります$list。つまり、bytecountに保存します$res。その後、次の項目を読み続けるのではなく、コマンドを実行して$listループbreakを終了します。

bytecount@ikkachuが言ったように、これを繰り返すよりも簡単に得る方法があります。

関連情報