Bash forループは「順序が間違っている」複数のechoステートメントを実行します。

Bash forループは「順序が間違っている」複数のechoステートメントを実行します。

Bashスクリプトがあります。

for j in "$(ls -d */)"; do 
    echo "$j"
    echo "$j"
done

出力:

dir1/
dir2/
dir3/
dir1/
dir2/
dir3/

私が出力したいのは次のとおりです。

dir1/
dir1/
dir2/
dir2/
dir3/
dir3/

どうすればこのように出力できますか?

(これはおもちゃの例です。本物私が望むのは、ディレクトリにCDを挿入し、何かをし、再びCDを挿入することです。文字列接続を使用して同じことができることに気づきましたが、この動作が混乱しすぎて他の質問が見つかりませんでした。それで尋ねるかと思いました。 )

答え1

あなたのループは一つ繰り返します。この繰り返しでは、変数jの値は次のとおりです。

dir1/
dir2/
dir3/

その後、2回出力します。

単一の文字列を繰り返すので、変数はこの値を取得しますls -d */

サブディレクトリを繰り返すには、次を使用します。

for dirpath in */; do
    printf '%s\n' "$dirpath"
    printf '%s\n' "$dirpath"
done

lslsつまり、まったく使う必要はありません(視力検査のみ)。

cd各反復ごとにディレクトリに入るには、サブシェルcdで実行し、そこで実行する必要があるすべての操作を実行します。これにより、cd現在の作業ディレクトリがサブシェルにローカルであるため、戻る必要はありません。

for dirpath in */; do
    ( cd -- "$dirpath" && some-command )
done

cd現在の作業ディレクトリを変更する必要がある場合にのみ入力してくださいsome-command。ほとんどの作業は元の作業ディレクトリで実行できます。

答え2

これは、実行中の出力を解析するls良い方法ではありません。

しかし、そう言うと、あなたの質問は次のように引用されます。

rm -rf dir?
for j in 1 2 3; do mkdir dir$j; done
for j in $(ls -d */); do 
    echo "$j"
    echo "$j"
done
dir1//
dir1//
dir2//
dir2//
dir3//
dir3//

投稿の引用符を使用すると、出力全体が引用ls符で囲まれているため、次のように処理されます。議論forループが一度だけ繰り返されるようにし、出力全体をls引数として使用します。あなたのコードは出力全体を2回印刷しますls

例を書くより良い方法lsは次のとおりです。

find . -type d -maxdepth 1 -mindepth 1 -exec printf '%s\n%s\n' "{}" "{}" \;

関連情報