Pushd-popdディレクトリリストを繰り返すときにif-fiセクションが必要ですか?

Pushd-popdディレクトリリストを繰り返すときにif-fiセクションが必要ですか?

私は次のコードを使用します。このスクリプト私はこれを使ってWordPressサイトを更新します。

#!/bin/bash
drt="/var/www/html"
for dir in ${drt}/*/; do
    if pushd "$dir"; then
        wp plugin update --all --allow-root
        wp core update --allow-root
        wp language core update --allow-root
        wp theme update --all --allow-root
    popd
    fi
done

すべてのWordPressインスタンスを一度に更新する方法を探している間、このコードで使用されている特定のパターンについて学びましたpushdpopd

このコードにセグメントが含まれている理由は不明ですif-fi

私の質問

基本的に、同じパターンを持つがif-fiセグメントがないように構文を何とか変更できますか?

たとえば、次のように変更します。

if pushd "$dir";
popd
    commands
fi

私は次の疑似コードを持っています:

pushd "$dir";
    commands
popd

私はこれをなぜ尋ねますか?

if-fi宣言(擬似コード)なしで、コンピュータに次のように話す方法を想像できます。

for dir in ${drt}/*; do pushd "$drt"; then
    commands
popd

ノート

  1. 答えに他のアプローチを含めることもできます(つまり、まったく含まれていません)pushdpopd

  2. 関連質問

答え1

また@Olorinによる投稿ここには少し誤解がある可能性があると思います。まずfor y in ${x}/*; do pushd "$y"; then、結果は

bash:予期しないトークン「then」の近くに構文エラーがあります。


第二に、インデントが誤解を招く可能性があります。実際に起こったことについて。元のコードの正しい形式のバージョン:

for y in ${x}/*/
do
    if pushd "$y"
    then
        command1
        command2
        popd
    fi
done

つまり、みんな command1、初期成功が発生した場合command2にのみ実行されます。代わりに書くならpopdpushd

for y in ${x}/*/
do
    pushd "$y"
    command1
    command2
    popd
done

そして、errexitガードがなければ、失敗pushdや失敗はpopdスクリプトの残りの部分に影響を与えません。これにより、間違ったディレクトリが実行され、command1入力されて別のディレクトリに戻る可能性があります。command2このコードとは何の関係もありません。これは悲惨な結果につながる可能性があります。


最後に言いたいことはpushd+コマンド+はpopdアンチパターンです言語にさらに多くのコンテキスト(したがって認知的オーバーヘッドとリスク)を追加し、複雑なコンテキストがすでに大きな問題であるためです。この問題を解決する最も一般的な方法は、次のようにコマンドにパス(絶対パスを推奨)を渡すことです。

for y in "$x"/*/
do
    command1 "$y"
    command2 "$y"
done

答え2

失敗するとpushdどうなりますか?これらのディレクトリでコマンドを実行する場合は、pushdコマンドを続行する前に成功するかどうかを明確に確認する必要があります。

答え3

ifを使用することは、ディレクトリ変更の失敗に対する合理的な保護です。

ディレクトリが実行可能でない場合(x権限なし)、このコードは親ディレクトリでコマンドを実行します。

#!/bin/bash
drt="/var/www/html"

for     dir in "${drt}"/*/
do      pushd "$dir"
        pwd
        popd
done

いくつかのディレクトリを構築し、所有者と権限を変更します。

$ mkdir -p /var/www/html/{one,two}
$ sudo chown user:user /var/www/html/{one,two}
$ sudo chmod o-x /var/www/html/two
$ ./script
/var/www/html/one ~/temp
/var/www/html/one
~/temp
./script: line 5: pushd: ./var/www/html/two/: Permission denied
~/temp
./script: line 7: popd: directory stack empty

Pushdコマンドはエラーを生成しますが、pwdコマンドは〜/ tempディレクトリから実行されます(エラー後に印刷される〜/ temp値に注意してください)。これは明らかに間違ったことをする危険があります。このスクリプトと比較してください。

#!/bin/bash
    drt="./var/www/html"

    for     dir in "${drt}"/*/
    do      if     pushd "$dir" 2>/dev/null
            then
                   pwd
                   popd
            fi
    done

新しいスクリプトが実行されました。

$ ./script
/var/www/html/one ~/temp
/var/www/html/one
~/temp

または、より良い方法は次のとおりです。

#!/bin/bash
drt="./var/www/html"

for     dir in "${drt}"/*/
do      if     pushd "$dir" 2>/dev/null
        then
               pwd
               popd
        else
                echo "Failed to change to dir=$dir" >&2
                exit 7
        fi
done

実行すると、次のように印刷されます。

$ ./script
/var/www/html/one ~/temp
/var/www/html/one
~/temp
Failed to change to dir=/var/www/html/two/

答え4

gnu-findを使用すると、次のことができます。

find ${drt} -maxdepth 1 -type d -execdir command1 ";" -execdir command2 ";"

すべてのfind実装に-execdirオプションがあるわけではありません。

関連情報