
以下のスクリプトの最初の~のためループは期待どおりに実行されますが、2番目のループは実行されません。エラーは発生しません。スクリプトが中断されたようです。
HOME=/root/mydir
DIR=$HOME/var
DIRWORK=$HOME/Local
for f in $(find $DIR -type f); do
lsof -n $f | grep [a-z] > /dev/null
if [ $? != 0 ]; then
echo "hi"
fi
done
for i in $(find $DIRWORK -type d -name work); do
echo "2"
done
答え1
あなたのスクリプトは危険な方法でコーディングされました。
まず、「/bash」と「/for」とマークしたので、Bashシェルを使用しているとします。
私の答えでは、私はこの素晴らしい言葉を引用します。強打ガイド、おそらくBashを学ぶのに最適なソースでしょう。
1)使用しないでくださいコマンドの置き換えの誰でもクラス、引用符なし。これには大きな問題があります。引用符なしで拡張を使用すると、出力はパラメータに分割されます。
具体的にはこの過程を経ます$(find $DIRWORK -type d -name work)
。$(find $DIR -type f)
噴射したがって、find
ファイル名にスペース、つまり「ファイル名」が含まれていると見つかった場合、Bashの単語分割の結果は、コマンドを繰り返すためのfor
2つのパラメータ、つまり「ファイル」と「名前」のパラメータを渡します。この場合、実際に存在する場合は破損するのではなく、「ファイル:対応するファイルまたはディレクトリなし」と「名前:対応するファイルまたはディレクトリなし」をインポートすることをお勧めします。
2)通常、環境変数(PATH、EDITOR、SHELL ...)と内部シェル変数(BASH_VERSION、RANDOM ...)はすべて大文字です。他のすべての変数名は小文字でなければなりません。変数名は大文字と小文字を区別するため、この規則は誤って環境変数と内部変数を上書きするのを防ぎます。
$DIRWORKディレクトリはその規則を破って引用符も解放されているため、許可すると、DIRWORK='/path/to/dir1 /path/to/dir2'
$ find
DIRWORKは引用符が解放されると2つの異なるディレクトリが表示されます。引用符を使用するトピックはBashで非常に重要であるため、「二重引用符」を使用する必要があります。すべて拡張や「$var」、「$@」、「${array[@]}」、「$(command)」などの特殊文字を含めることができるすべての項目。 Bashは「一重引用符」内のすべての内容をリテラルとして扱います。 '、'、`の違いを調べてください。引用符、議論次のリンクを確認してください。http://wiki.bash-hackers.org/syntax/words
これはより安全なスクリプトバージョンなので、代わりに使用することをお勧めします。
my_home="/root/mydir"
my_dir="$my_home/var"
dir_work="$my_home/Local"
while IFS= read -r -d '' f; do
# I'm guessing that you also want to ignore stderr;
# this is where the 2>&1 came from.
if lsof -n "$f" | grep '[a-z]' > /dev/null 2>&1; then
echo "hey, I'm safer now!"
fi
done < <(find "$dir_work" -type f -print0)
while IFS= read -r -d '' f; do
echo "2"
done < <(find "$dir_work" -type d -name 'work' -print0)
ご覧のとおり、このIFS
変数は空の値に設定されており、read
行の先頭と末尾のスペースが切り捨てられないようにします。このread
コマンドは、空の文字列(-d ''
)を区切り文字として使用し、\ 0に達するまで読み取ります。
find
それに応じて変更する必要があるため、新しい-print0
行ではなく\ 0でデータを区切るオプションを使用します。驚くべきことに、悪意のあるファイル名の一部になる可能性があります。これらのファイルを\ nを使用して2つの部分に分割すると、コードが破損します。
あなたはについて読んでみたいかもしれませんプロセスの交換私のスクリプトを完全に理解していない場合。
find ... | while read name; do ...; done
出力を読み取るために使用する必要があるという以前の答えfind
も悪いかもしれません。上記のループは、while
親シェルからコピーされた変数コピーを使用して新しいサブシェルで実行されます。その後、そのコピーを目的の目的に使用できます。ループが終了すると、while
サブシェルのコピーが削除され、親シェルの元の変数は変更されません。
目標がwhile
このループ内のいくつかの変数を変更し、後で親で使用することである場合は、上記のより安全なスクリプトを使用することをお勧めします。これにより、データの損失を防ぐことができます。
答え2
このコード
for i in $(find $DIRWORK -type d -name work); do
echo "2"
done
この行を最初に実行します
find $DIRWORK -type d -name work
実行が完了するのを待ってから、find
出力を取得してfor
ループに戻します。
for i in the output of find; do
echo "2"
done
これでforループの実行が開始されます。
したがって、ループをfind
完了するのに長い時間がかかる場合は、for
開始する前に長い時間を待つ必要があります。
find
対話型プロンプトでタイミングコマンドを試してください。
$ time find $DIRWORK -type d -name work
時間がどれくらいかかるかを確認してください。
さらに注:for
ループはファイル名を繰り返すために使用しないでください。次のループを使用してくださいwhile
。read
find $DIRWORK -type d -name work | while read name; do
echo "2"
done
読むこれより多くの情報を知りたいです。
ボーナス:これはwhile
ループを並列に実行するために使用されますfind
。これは、ループが1行を印刷したwhile
直後に1回の反復を実行することを意味します。実行が完了するまでfind
待つ必要はありませんfind
。