함수의 "cd"는 그렇지 않은 경우를 제외하고는 작동합니다.

함수의 "cd"는 그렇지 않은 경우를 제외하고는 작동합니다.

디렉토리에 CD를 넣은 후 제가 가장 먼저 한 일은 "ls"를 사용하는 것이었습니다. 많은 사람들이 그렇게 한다고 생각합니다. 그래서 두 작업을 모두 수행하기 위해 .bashrc에 함수를 정의하기로 결정했습니다. 이것이 내가 생각해낸 것입니다:

cs() {
    if [[ ! "$1" ]] && [[ ! "$HOME" ]]
    then
        echo "I am completely lost and can't go home!"
        exit 1
    fi
    cd "$1" && ls --group-directories-first -h --color=auto
}

이는 매개 변수를 전달하지 않는 경우를 제외한 모든 경우에 작동합니다. $HOME 설정 여부에 관계없이 아무 작업도 수행하지 않고 종료됩니다. 나는 첫 번째 줄을 분해하여 다음과 같은 결과를 얻었습니다.

cs() {
    if [[ ! "$1" ]]
    then
        if [[ ! "$HOME" ]]
        then
            echo "I am completely lost and can't go home!"
            exit 1
        else
            cd && ls --group-directories-first -h --color=auto
        fi
    else
        cd "$1" && ls --group-directories-first -h --color=auto
    fi
}

이 코드는 예상한 대로 정확하게 작동합니다. 그 사이에 매우 이상한 동작을 하는 버전이 있습니다(불행히도 저장했지만 두 버전 간의 차이는 매우 작습니다). 여기서 매개변수로 "cs"를 발생시키면 디렉토리의 "ls"가 출력됩니다. .. 하지만 디렉토리는 변경되지 않습니다! 코드는 "cd"에 인수만 전달하고 ls는 현재 디렉터리에서 작업하는 기본 동작으로 돌아가기 때문에(이 누락된 버전에서도 마찬가지였습니다), " ls"를 동일한 코드 블록에 포함시키는 것인데, 내가 아는 한 그것은 불가능할 것입니다.

나는 여기서 무슨 일이 일어나고 있는지 이해하고 싶습니다. 이제 막 스크립트를 배우기 시작했는데 아주 간단한 작업일 줄 알았는데 정말 좋은 학습 기회가 된 것 같습니다. 나에게는 거의 동일해 보이는 이 기능들이 왜 다르게 동작하는 걸까요?

답변1

cd함수에 제공된 원래 인수 목록을 사용하여 실행한 다음 명령을 실행 하면 됩니다 ls.

cs () {
    cd "$@" && ls --group-directories-first --human-readable --color=auto
}

인수 없이 함수를 호출하면 확장이 "$@"전혀 발생하지 않아 cd현재 사용자의 홈 디렉터리가 변경되거나 적절한 방식으로 실패하게 됩니다. 그렇지 않으면 확장은 인용된 인수 목록이 됩니다( cd종종 여러 인수를 사용할 수 있다는 점에 유의하세요).

명령의 내부 논리는 cd인수를 수신하지 않고 설정하지 않는 경우를 이미 처리하므로 HOME함수가 포함될 필요가 없습니다.

exit일반적으로 함수 내에서 이를 사용 하지 않는 것이 좋습니다 . 이렇게 하면 현재 쉘이 종료되기 때문입니다. 반대로, 함수에서 0이 아닌 종료 상태를 반환하려면 return 1다음을 사용하세요.

디렉토리 변경이 성공하지 못했다 는 귀하의 의견은 다음과 같습니다 . 또는 (파이프라인의 각 부분이 서브셸에서 실행됨) 과 같이 서브셸에서 cd함수를 실행하는 경우 cd이런 일이 발생할 수 있습니다 . 호출이 성공했습니다. 현재 디렉토리(cd /)cat somefile | while ...; do cd ...; donecd변경되었지만 하위 셸의 로컬 환경이 변경되었으며 상위 셸에는 표시되지 않습니다. 하위 쉘은 상위 쉘의 환경을 변경할 수 없습니다.

답변2

cs() {
    ...
    cd "$1" && ls --group-directories-first -h --color=auto
}

이는 매개 변수를 전달하지 않는 경우를 제외한 모든 경우에 작동합니다.

매개변수가 없으면 $1설정되지 않습니다(예 $2: , $3, ...). 그러나 설정되지 않은 매개변수를 따옴표로 묶어 확장하면 "$1"null 값이 있는 매개변수와 동일하게 동작합니다. 즉, 빈 문자열로 확장됩니다. 이는 또는 lsls ""비교하는 등 매개변수가 없는 것과는 다릅니다 unset foo; ls "$foo".

의 경우 cdBash의 동작은 cd인수가 없는 호출은 현재 디렉터리로 이동하는 $HOME반면 cd빈 문자열을 인수로 사용하는 호출은 자동으로 현재 디렉터리로 이동하는 것입니다.

(사용하는 경우 쉘에 따라 다릅니다 -P. 인수가 빈 문자열인 경우 기본 chdir()함수 호출은 오류를 제공해야 하며 Bash는 를 사용하여 해당 오류를 노출하는 것처럼 보입니다 cd -P. 일부 다른 쉘은 chdir()대상 .또는 현재 디렉토리만 제공하는 반면 ksh는 cd ""및 "잘못된 디렉토리" 오류 cd -P "")

함수의 모든 매개변수를 에 전달하려면 를 cd사용하십시오 cd "$@". 하나의 문자열을 생성하는 다른 큰따옴표 확장과 달리, "$@"위치 인수 전체가 다른 문자열로 생성됩니다(또는 다른 쉘 "단어"로 인해 명령에 대한 다른 인수가 발생함). 따라서 인수가 없으면 은 cd "$1"just 와 동일하며 cd ""이는 cd "$@"just 와 동일합니다 cd.

$HOME 설정 여부에 관계없이 아무 작업도 수행하지 않고 종료됩니다.

왜 테스트가 작동하지 않는지 이해할 수 없으므로 $HOME이에 대해서는 언급하지 않겠습니다.

관련 정보