本から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"
または、ファイル名をに渡すのではなく、ファイルをwc
stdinにリダイレクトしてファイル名を出力しません。wc
wc
$ 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が言ったように、これを繰り返すよりも簡単に得る方法があります。