서브 쉘을 사용하지 않고 쉘 명령 대체를 수행 할 수 있습니까?


11

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

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; }

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

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


1
디렉토리를 변수에 저장합니다. 이런 식으로 trap처리기는 신호에 의해 프로세스를 찌를 경우 디렉토리를 정리할 수 있습니다.
thrig

대답은 ' 아니요' 입니다.
h0tw1r3

fish명령 대체에 해당하는 on 모양 ()은 외부 쉘의 폴더를 변경합니다. 그것은 일반적으로 성가 시지만, 이와 같은 경우에는 유용합니다.
trysis

답변:


10

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

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)"

나는 당신이 설명하고 그들이 명령 대체와 독립적이라는 것을 이해 pushd하고 popd일합니다. 그러나을 공개하여 자신의 문제로 대답했습니다 $OLDPWD. 할 수 있습니다 popd; rmdir $OLDPWD. 그것은 내 문제에 대한 답입니다-다른 모든 것들은 단지 내가 생각한 것을 확인합니다. 명령 대체는 그것을 해결하는 방법 인 것처럼 보이지만 하위 쉘 때문이 아니므로 하위 쉘없이 명령 대체를 수행 할 수 없으므로 OLDPWD를 공개 해 주셔서 감사합니다. 정확히 필요한 것입니다!
starfry

@starfry, rmdir $(popd)원인 popd은 현재 디렉토리를 변경하지 않습니다 의미 서브 쉘에서 실행하지만,이 서브 쉘에서 실행되지 않은 경우에도의 출력이 popd임시 디렉토리되지 않습니다, 그것은 공간이 분리 된 목록이 될 것입니다 임시 디렉토리를 포함하지 않는 디렉토리 내가 당신이 혼란스러워 말하는 곳입니다.
Stéphane Chazelas

그러나 나는 내 질문에 "popd는 팝 된 디렉토리를 반환하지 않으며 (현재, 새로운 디렉토리를 반환한다) 또한 서브 쉘에서 수행되기 때문에"라고 말했다. 틀림없이 그것은 목록을 반환하지만 목록의 첫 번째는 내가 언급 한 것입니다.
starfry

@starfry 죄송합니다. 내가 질문의 제목에 혼란스러워서 나머지를 충분히 읽지 않았다고 가정 해 봅시다.
Stéphane Chazelas

글쎄, 당신의 대답은 여전히 ​​좋았고 올바른 방향으로 나를 가리 켰습니다. 나는 그 쉘 변수에 대해 전혀 몰랐다 OLDPWD. 언젠가 man bash끝까지 읽은 것을 기억해야합니다 !
starfry

2

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

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

또는

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

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


0

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 ~-

이것에 대한 문제와 내가 해결하려고 rmdir했던 것은 이것을 할 때 현재 디렉토리가 될 수 없다는 것입니다. popd수행하기 전에 에 영향 rmdir을 주어야하지만 무엇을 제거해야하는지 알고 있어야 popd합니다. 나는 당신과 같이 dirs -l -1대답 이라고 생각 했지만 그 대답이 실제로 사용된다는 것을 발견했습니다 $OLDPWD.
starfry

@starfry 가장 짧은 대답은 다음을 사용하는 것 popd && rmdir ~-입니다.

@starfry 현재 디렉토리가 비어 있으면 (지우지 않고) 디렉토리를 실제로 제거 할 수 있습니다. 당신은 부를 수있는 rmdir "$PWD"모든 권리. 또한 현재 디렉토리는 mktmp -d( pushd $(mktemp -d)미리 실행 된 경우) 작성 pushd하고 pwd 를 이동시키는 디렉토리 여야합니다 . 그래서, 그래, pushd전에 popd를, 생성 된 디렉토리에 저장되어 $(dirs -1), 나는 어떤 문제를보고 실패합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.