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 인스턴스를 한 번에 업데이트하는 방법을 찾던 중 이 코드에서 사용된 특정 패턴에 대해 배웠습니다 pushd.popd

이 코드에 세그먼트가 포함된 이유가 확실하지 않습니다 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. 답변에 다른 접근 방식을 포함할 수도 있습니다(즉, 전혀 포함하지 않음) pushd.popd

  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 옵션이 있는 것은 아닙니다.

관련 정보