">>"演算子が私のスクリプトで正しく動作しないことがわかりましたが、その理由はわかりません。次のスクリプトがあります。
for file in $(ls folder)`
do
echo $file >> text.txt
done
入力するフォルダ91個の要素がありますが、最初の87個の要素のみが挿入されました。ファイル.txt。このコードに何が問題なのかわかりません。理解するのに役立ちますか?
編集する
私が書いたシナリオはとても簡単でしたが、状況を明確に説明できないことがわかりました。詳細は次のとおりです。
私のフォルダには91個のcsvファイルがあり、各ファイルには名前と値の2つの列が含まれています。各ファイルの値が2.500より大きいか0.000でないかを制御する必要があります。これら2つの条件のいずれかがtrueの場合は、削除したファイルを含むtxtファイルにファイル名とその値を追加し、そうでない場合は、選択したファイルを含むcsvファイルにファイル名とその値を追加します。値を制御するために使用するコードはうまく機能しますが、>>を使用して結果をtxtまたはcsvファイルに追加すると、最後の4つの結果が追加されず、理由を理解できません。
for file in $(ls folder)
do
value=$(cat path/$file | awk -F, '{print $2}')
discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')
if [[ $discard -eq 1 || $discard -eq 0 ]]
then
echo ""$file" has value="$value"" >> path/discard.txt
rm path/"$file"
else
echo ""$file",$value" >> path/selected.csv
rm path/"$file"
fi
done
ここに私のスクリプトのより完全なバージョンがあります。
編集2
見つかった問題を解決するためにスクリプトを修正しました。それでも同じ問題です。より明確に言えば、私のフォルダ内のファイルはプログラムによって自動的に生成されるcsvファイルであり、IDと浮動小数点値という1つの行と2つの列のみを含みます。それらはすべて非常に似ているので、端末でスクリプトがそれを認識してうまく処理するのを見ることができるので、問題はありません。私はなぜ追加が最後の4つのファイルをtxtファイルに入れないのか分かりません。
for file in folder/*
do
value=$(cat "$file" | awk -F, '{print $2}')
discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')
if [[ "$discard" -eq 1 || "$discard" -eq 0 ]]
then
echo ""$file" has value="$value"" >> path/discard.txt
rm -- "$file"
else
echo ""$file",$value" >> path/selected.csv
rm -- "$file"
fi
done
ファイル数を減らすと正常に動作します。
答え1
これには2つの主な問題があります。
絶対にしないでしょう
for file in $(ls)
。これもバッシュトラップ番号1。まず、壊れやすく、見てわかるように、少し奇妙なファイル名でも破損する可能性があります。悪いことはまったく必要ではなく、コードを必要以上に脆弱で複雑にすることです。あなたはこれを行うことができますfor file in *
。常に変数を引用してください。これは、次のようなファイル名を処理するときに特に重要です。どの文字を除く
\0
。そして/
。変数を引用しないと、シェルは変数を拡張するため、スペースが含まれている場合、シェルは1つではなく2つの値を表示します。たとえば、
これを説明するために、次の2つのファイルを含むディレクトリを考えてみましょう。
$ touch 'a file2' 'file1 *'
$ ls -l
total 0
-rw-r--r-- 1 terdon terdon 0 Sep 22 17:39 'file1 *'
-rw-r--r-- 1 terdon terdon 0 Sep 22 17:39 'a file2'
さて、元のコードを試してみると、次のような結果が得られます。
$ for file in $(ls); do echo $file; done
a
file2
file1
a file2
file1 a file2 file1 *
これは、参照がないため、シェルがa
次file2
をfile1
受け取るためです*
。したがって、各ファイルは個別に処理され、echo *
最後に実行されたときにディレクトリのすべての内容が再印刷されます。しかし、正しい方法で行うと、すべてが機能します。
$ for file in *; do echo "$file"; done
a file2
file1 *
以下はスクリプトの動作バージョンです(最初にテストしてみてください。データは表示できません)。
for file in folder/*
do
value=$(awk -F, '{print $2}' "$file")
discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')
if [[ $discard -eq 1 || $discard -eq 0 ]]
then
printf '"%s" has value="%s"' "$file" "$value" >> path/discard.txt
rm -- "$file"
else
printf '"%s",%s' "$file" "$value" >> path/selected.csv
rm -- "$file"
fi
done
答え2
削除された要素を処理するために、TXTファイルの代わりにCSVファイルを使用してみました。これでスクリプトが正常に実行されます。
for file in folder/*
do
value=$(cat "$file" | awk -F, '{print $2}')
discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')
if [[ "$discard" -eq 1 || "$discard" -eq 0 ]]
then
echo ""$file" has value="$value"" >> path/discard.csv
rm -- "$file"
else
echo ""$file",$value" >> path/selected.csv
rm -- "$file"
fi
done
あなたの助けと助言に感謝します!