서브 쉘을 사용하지 않고 쉘 명령 대체를 수행 할 수 있습니까? 요구하는 시나리오가 있습니다. 나는 이와 같은

서브 쉘을 사용하지 않고 명령 대체를 요구하는 시나리오가 있습니다. 나는 이와 같은 구조를 가지고있다 :

pushd $(mktemp -d)

이제 임시 디렉토리를 종료하고 한 번에 제거하고 싶습니다.

rmdir $(popd)

그러나 popd팝 된 디렉토리를 반환하지 않고 (현재 새로운 디렉토리를 반환) 하위 쉘에서 수행되기 때문에 작동 하지 않습니다.

같은 것

dirs -l -1 ; popd &> /dev/null

팝 된 디렉토리를 반환하지만 다음과 같이 사용할 수 없습니다 :

rmdir $(dirs -l -1 ; popd &> /dev/null)

popd서브 쉘에만 영향을 미치기 때문 입니다. 요구되는 것은 이것을 할 수있는 능력이다 :

rmdir { dirs -l -1 ; popd &> /dev/null; }

그러나 그것은 잘못된 구문입니다. 이 효과를 얻을 수 있습니까?

(참고 : 임시 디렉토리를 변수에 저장할 수 있다는 것을 알고 있습니다. 필요하지 않고 프로세스에서 새로운 것을 배우려고했습니다!)



답변

질문 제목을 선택하는 것은 약간 혼란 스럽습니다.

pushd/ popd하는 csh기능에 의해 복사 bash하고 zsh, 기억 디렉토리의 스택을 관리하는 방법입니다.

pushd /some/dir

푸시 현재 스택 상 작업 디렉토리, 그리고 다음 인쇄합니다 후 현재 디렉토리를 변경하는 (그리고 /some/dir그 스택의 콘텐츠 하였다 () 공간으로 구분.

popd

스택의 내용을 다시 인쇄하고 (격리 된 공간) 스택의 맨 위 요소로 변경하여 스택에서 튀어 나옵니다.

(또한 일부 디렉토리는 해당 디렉토리 ~/x또는 ~user/x표기법 으로 표시 될 것입니다 ).

스택은 현재 보유하고 경우에 따라서 /a하고 /b, 현재 디렉토리는 /here당신이 실행중인 :

 pushd /tmp/whatever
 popd

pushd인쇄 할 /tmp/whatever /here /a /bpopd의지 출력을 /here /a /b하지 /tmp/whatever. 그것은 명령 대체를 사용하는 것과 무관합니다. popd이전 디렉토리의 경로를 얻는 데 사용할 수 없으며 일반적으로 출력을 포스트 처리 할 수 ​​없습니다 ( 해당 디렉토리 스택의 요소에 액세스하려면 일부 쉘의 배열 $dirstack또는 $DIRSTACK배열 참조 )

어쩌면 당신은 원할 것입니다 :

pushd "$(mktemp -d)" &&
popd &&
rmdir "$OLDPWD"

또는

cd "$(mktemp -d)" &&
cd - &&
rmdir "$OLDPWD"

그래도 사용합니다 :

tmpdir=$(mktemp -d) || exit
(
  cd "$tmpdir" || exit # in a subshell 
  # do what you have to do in that tmpdir
)
rmdir "$tmpdir"

어쨌든 서브 쉘에서 pushd "$(mktemp -d)"실행되지 않습니다 pushd. 그렇다면 작업 디렉토리를 변경할 수 없습니다. 그것이 mktemp서브 쉘에서 실행됩니다. 별도의 명령이므로 별도의 프로세스에서 실행해야합니다. 파이프에 출력을 기록하고 쉘 프로세스는 파이프의 다른 쪽 끝에서 출력을 읽습니다.

ksh93은 명령이 내장되어있을 때 별도의 프로세스를 피할 수 있지만, 여전히 포킹으로 제공되는 별도의 환경에 의존하기보다는 서브 쉘 (다른 작업 환경)이 에뮬레이트됩니다. 예를 들어,에 ksh93, a=0; echo "$(a=1; echo test)"; echo "$a"어떤 포크는 아직 포함되지되지만 echo "$a"출력 0.

당신의 출력을 저장하려면 여기, mktemp당신이 그것을 통과 동시에 변수에, pushd로를 zsh, 당신은 할 수 있습니다 :

pushd ${tmpdir::="$(mktemp -d)"}

다른 Bourne과 같은 껍질 :

unset tmpdir
pushd "${tmpdir=$(mktemp -d)}"

또는 $(mktemp -d)변수에 명시 적으로 저장하지 않고 여러 번 출력을 사용하려면 zsh익명 함수를 사용할 수 있습니다 .

(){pushd ${1?} && cd - && rmdir $1} "$(mktemp -d)"

답변

디렉토리를 떠나기 전에 먼저 링크를 해제 할 수 있습니다.

rmdir "$(pwd -P)" && popd

또는

rmdir "$(pwd -P)" && cd ..   # yes, .. is still usable

하지만 참고 pushdpopd되지 스크립트에 대한 대화 형 쉘 도구는 정말 (그들이 그렇게 수다스러운 이유의 것을 그들은 성공할 때 실제 스크립트 명령이 침묵).


답변

bash dirs에서 pushd / popd 메소드로 기억 된 디렉토리 목록을 제공하십시오.

또한 dirs -1목록에 포함 된 마지막 디렉토리를 인쇄합니다.

따라서를 실행하여 이전에 만든 디렉토리를 제거 pushd $(mktmp -d)하려면 다음을 사용하십시오.

rmdir $(dirs -1)

그런 다음 popd목록에서 이미 제거 된 디렉토리 :

popd > /dev/null

한 줄에 모두 :

rmdir $(dirs -1); popd > /dev/null

~/x또는 ~user/x표기법 을 피하기 위해 옵션 (-l)을 추가하십시오 .

rmdir $(dirs -l -1); popd > /dev/null

요청한 라인과 매우 유사합니다.
를 사용 &>하여 오류보고를 숨길 수 있다는 점을 제외하고 popd.

주 : 디렉토리 후 남아 rmdir는 그대로 pwd그 시점에서. 그리고 popd명령 후에 실제로 연결이 해제됩니다 (남은 링크는 사용되지 않음).


변수 “OLDPWD”를 지원하는 쉘 (대부분의 본과 같은 쉘 : ksh, bash, zsh have $OLDPWD) 에 사용할 수있는 옵션이 있습니다 . 그 흥미 롭다 DIRS, 포드, PUSHD 기본적으로 구현하지 않습니다 KSH (사용할 수 있으므로, 여기에 사용할 수 없습니다 또한 popd 명령이없는 lksh, 대시 등을) :

popd && rmdir "$OLDPWD"

또는 더 관용적 인 (위와 같은 쉘 목록) :

popd && rmdir ~-