CD를 함수에 로컬로 만들 수 있나요?

CD를 함수에 로컬로 만들 수 있나요?

비슷한 기능을 만들 수 있을까요?

function doStuffAt {
    cd $1
    # do stuff
}

하지만 함수를 호출한다고 해서 실제로 내 비밀번호가 변경되는 것은 아니며, 함수가 지속되는 동안만 변경된다는 뜻인가요? 비밀번호를 저장하고 마지막에 다시 설정할 수 있다는 것을 알고 있지만, 이에 대해 걱정할 필요 없이 로컬에서 비밀번호를 설정할 수 있는 방법이 있기를 바랐습니다.

답변1

예. 그룹 명령 ( )대신 하위 쉘에서 함수가 명령을 실행하도록 하세요 .{ }

doStuffAt() (
        cd -- "$1" || exit # the subshell if cd failed.
        # do stuff
)

대괄호( ( ))는 상위 쉘의 환경을 상속하는 새 하위 쉘을 엽니다. 하위 셸을 실행하는 명령이 완료되면 종료되어 상위 셸로 돌아가며 cd하위 셸에만 영향을 미치므로 PWD는 변경되지 않습니다.

서브쉘은 모든 쉘 변수도 복사하므로 전역 변수를 통해 서브쉘 함수의 정보를 기본 스크립트로 다시 전달할 수 없습니다.

서브셸에 대한 자세한 내용은 다음을 확인하세요 man bash.

(목록)

list는 서브셸 환경에서 실행됩니다(아래 명령 실행 환경 참조). 쉘 환경에 영향을 미치는 변수 할당 및 내장 명령은 명령이 완료된 후에 더 이상 유효하지 않습니다. 반환 상태는 목록의 종료 상태입니다.

비교:

{ 목록; }

list는 현재 쉘 환경에서만 실행됩니다. 목록은 줄 바꿈 또는 세미콜론으로 끝나야 합니다. 이를 그룹 명령이라고 합니다. 반환 상태는 목록의 종료 상태입니다. 메타 문자( 및 )와 달리 { 및 }는 예약어이므로 예약어를 인식할 수 있는 위치에 나타나야 합니다. 단어 분리를 유발하지 않으므로 공백이나 기타 쉘 메타 문자로 목록과 구분해야 합니다.

답변2

때에 따라 다르지.

이 기능을서브쉘. (당신은 또한 볼 수 있습니다대괄호는 실제로 명령을 하위 쉘에 넣습니까?) 서브쉘에서 일어나는 일은 서브쉘 내에 유지됩니다. 변수, 현재 디렉터리, 리디렉션, 트랩 등에 대한 함수의 변경 사항은 호출 코드에 영향을 주지 않습니다. 하위 셸은 상위 셸에서 이러한 모든 속성을 상속하지만 다른 방향으로 전달되지는 않습니다. exit서브쉘에서는 호출 프로세스가 아닌 서브쉘만 종료합니다. 코드 조각을 괄호로 묶어 서브셸에 넣을 수 있습니다(괄호 앞과 뒤의 줄 바꿈 및 공백은 선택 사항입니다).

(
  set -e # to exit the subshell as soon as an error happens
  cd -- "$1"
  do stuff # in $1
)
do more stuff # in whatever directory was current before the '('

서브셸에서 전체 함수를 실행하려면 중괄호 대신 괄호를 사용하여 함수 코드를 래핑할 수 있습니다.

doStuffAt () (
    set -e
    cd -- "$1"
    # do stuff
)

Korn 스타일 함수 정의 구문을 사용하려면 다음을 수행해야 합니다.

function doStuffAt { (
    set -e
    cd -- "$1"
    # do stuff
) }

서브쉘의 단점은 아무것도 이를 벗어날 수 없다는 것입니다. 현재 디렉터리를 변경한 후 일부 변수를 업데이트해야 하는 경우 하위 쉘을 사용하여 이를 수행할 수 없습니다. 서브쉘에서 정보를 검색하는 간단한 방법은 두 가지뿐입니다. 다른 명령과 마찬가지로 서브쉘에도 종료 상태가 있지만 이는 0에서 255 사이의 정수이므로 많은 정보를 전달하지 않습니다. 당신은 그것을 사용할 수 있습니다명령 대체일부 출력 생성: 명령 대체는 표준 출력(후행 개행 제외)이 문자열로 수집되는 하위 쉘입니다. 이를 통해 문자열을 출력할 수 있습니다.

data=$(
  set -e
  cd -- "$1"
  do stuff # in $1
)
# Now you're still in the original directory, and you have some data in $data

현재 디렉터리를 변수에 저장하고 나중에 복원할 수 있습니다.

set -e
old_cwd="$PWD"
cd -- "$1"
cd "$old_cwd"

그러나 이 방법은 신뢰성이 떨어집니다. 코드가 cd두 명령 사이에 있으면 잘못된 디렉터리에 있게 됩니다. 이 시간 동안 이전 디렉터리가 이동된 경우 두 번째 명령은 cd올바른 위치로 돌아가지 않습니다. 변경할 권한이 없는 디렉터리에 있을 수 있습니다(스크립트가 호출자보다 권한이 낮기 때문). 이 경우 두 번째 명령이 cd실패합니다. 따라서 통제된 환경에 있지 않는 한 이 작업(예: cd스크립트로 생성된 임시 디렉터리에 들어가고 나가기) 을 수행해서는 안 됩니다.

일시적으로 디렉터리를 변경하고 어떤 방식으로든(예: 변수 설정) 셸 환경에 영향을 주어야 하는 경우 스크립트를 셸 환경에 영향을 미치는 부분과 현재 디렉터리를 변경하는 부분으로 조심스럽게 분리해야 합니다. 셸은 이전 Unix 시스템의 제한 사항을 상속받으며 이전 디렉터리로 돌아갈 수 없습니다. 최신 UNIX 시스템에서는 그렇게 하지만(현재 디렉터리의 파일 설명자를 "저장"하고 fchdir()예외 처리기에 반환할 수 있음), 이 기능을 위한 쉘 인터페이스는 없습니다.

답변3

일부 작업을 수행하기 위해 "일시적으로" 디렉토리에 들어갈 때(IOW, 어떤 방식으로든 디렉토리 변경 범위를 제한하려는 경우) 해당 디렉토리를 활용하는 것이 합리적입니다.더미pushd및 를 사용하는 popd것은 빌드 스크립트와 같은 영역에서 일반적인 기술입니다.

당신이 많은 플러그인을 만들고 있다고 가정해 봅시다.

for plugindir in plugin1 plugin2 plugin2 plugin4; do
  pushd -- "$plugindir"
  make
  popd
done

답변4

서브쉘에서 호출하세요.

(doStuffAt some/path/)

관련 정보