zsh가 마지막으로 실행 한 프로그램의 표준에 액세스 할 수 있습니까?


16

나는 종종 경로를 찾 find거나 사용 locate합니다.

(~) locate foobar.mmpz
/home/progo/lmms/projects/foobar.mmpz

다음 단계는 종종 파일을 열거 나 조작하는 것입니다. 위와 같은 행복한 경우에는 다음과 같이 할 수 있습니다.

(~) ls `!!`
ls `locate foobar.mmpz`
/home/progo/lmms/projects/foobar.mmpz

그러나 생산 라인이 많을 때 아무도 행복하지 않습니다. 그 중 일부는 경로 나 다른 종류의 것이 아닐 수도 있습니다. 게다가 잠재적으로 쓸데없는 명령을 다시 실행하는 것도 그다지 우아하지 않습니다.

나중에 조작하기 위해 zsh를 연결하여 stdout을 배열에 저장하는 방법이 있습니까? 결국 스트림을 사용자에게 리디렉션하는 것은 쉘의 일입니다. 첫 번째 N 줄과 마지막 N 줄을 나중에 나중에 사용할 수 있도록 변수에 저장할 수 있다고 생각합니다 $?.

좋아, 이것은 꽤 멋지다 : /unix//a/59704/5674 . 이제 각 실행 라인 후에 이러한 종류의 캡처를 조작하기 위해 zsh 노하우 (및 코드를 zsh로 이식)에 대해 묻고 있습니다.


스트림을 사용자에게 리디렉션하는 것은 실제로 쉘의 일이 아닙니다. 응용 프로그램은 터미널 장치에 출력을 기록하지만 셸은 관련이 없습니다.
Stéphane Chazelas

@StephaneChazelas, 그러나 사용자 요청에 따라 스트림을 파일로 리디렉션하는 것이 쉘의 역할입니다. 또한 stdout과 구분하기 위해 빨간색으로 표시되는 zsh에 대한 레시피가 있습니다. 스트리밍 문제에서 쉘의 역할을 나타내는 것 같습니다.
unperson325680

예, screenor script및 precmd 및 preexec 후크를 사용하여 수행 할 수 있습니다.
Stéphane Chazelas

답변:


7

대부분의 터미널 에뮬레이터에서 화면의 출력을 캡처하는 기능은 없습니다. xterm ( "참조"터미널 에뮬레이터)의 저자는 구현하기가 어렵다고 언급 한 것을 기억합니다. 이것이 가능하더라도 쉘은 마지막 프롬프트가 어디에 있는지 추적해야합니다.

따라서 xterm의 마우스 또는 화면의 키보드를 사용하여 복사 붙여 넣기와 같은 터미널 별 수동 메커니즘을 사용하지 않으면 명령을 다시 실행하지 않아도됩니다.

쉘이 명령 출력을 자동으로 캡처하는 것은 실용적이지 않습니다. 복잡한 터미널 및 사용자 상호 작용이있는 명령과 단순히 인쇄 가능한 문자를 출력하는 명령을 구별 할 수 없기 때문입니다.

명령을 다시 실행하고 출력을 캡처 할 수 있습니다. 각각을 수행하는 다양한 방법이 있습니다. 명령을 다시 실행하려면 다음을 사용할 수 있습니다.

  • !! 기록 대체-가장 입력하기 편리합니다.
  • fc -e -함수에서 사용할 수 있습니다.

출력을 캡처하려면 명령 대체 또는 다음과 같은 기능을 사용할 수 있습니다.

K () {
  lines=("${(f@)$(cat)}")
}
!! |K

이렇게하면 lines배열 이 파이프 된 명령의 출력으로 설정됩니다.


그러면 그렇게 해. 나는 완전히 자동적 인 접근 방식이 너무 어려우며, 두 번째로 가장 좋은 것은 K당신의 것과 비슷하다는 것을 잘 설명하고 있습니다.
unperson325680

3

다음은 출력이라는 마지막 변수를라는 변수에 넣을 첫 컷입니다 $lastline.

precmd () {                                                                                                                                                                                                        
    exec 2>&- >&-
    lastline=$(tail -1 ~/.command.out) 
    sleep 0.1   # TODO: synchronize better
    exec > /dev/tty 2>&1
}

preexec() {
    exec > >(tee ~/.command.out&)
}

이 용도의 zsh을 preexec실행 후크 exectee다음 사용을 명령의 표준 출력의 사본을 저장하기를precmd 저장 출력을 읽고 프롬프트를 보여주는 바로 터미널로 표준 출력을 복원 할 수 있습니다.

그러나 여전히 약간의 작업이 필요합니다. 표준 출력이 더 이상 터미널이기 때문에 예를 들어, 같은 프로그램 vim과는 less제대로 작동하지 않습니다.

이 질문에는 유용한 관련 정보가 있습니다.


예, 100 % 자동 접근 방식이 작동하지 않을 수 있습니다. exec코드에 많은 호출이 있거나 명령이 여러 번 실행되고 있습니까? 아니면 특수 의미에 잡혀 있습니까?
unperson325680

exec프로그램 이름이 없으면 리디렉션 만 설정합니다.
Mikel

2

결과를로 파이핑 tee하면 출력을 파일로 저장하고 동시에 표시 할 수 있습니다.

예를 들어, 출력을 평상시처럼 보여줄뿐 아니라 파일에 저장합니다. /tmp/it

locate foobar.mmpz | tee /tmp/it

그런 다음 해당 파일을 분류하고 항목을 선택하도록 grep하십시오.

cat /tmp/it | grep progo | grep lms

그런 다음 사용하려면 다음과 같이하십시오.

vi $(!!)


2

나는이 반 구운 솔루션을 생각해 냈습니다.

alias -g ___='"$(eval "$(fc -ln -1)" | tail -n 1)"'

이를 통해 ___명령 줄의 어느 시점에서나 쓸 수 있습니다 . 이전 명령이 다시 실행되고이 명령은 ___출력의 마지막 줄로 바뀝니다. 사용법 예 :

$ touch foo bar baz
$ ls -1
bar
baz
foo
$ vim ___

마지막 명령이로 확장됩니다 vim foo.

이것은 날카로운 모서리가 있습니다!

  • 당신이 포함 된 경우 ___명령이 아니라 이전 명령도 포함 ___, 쉘은 잠시 동안 몇 가지 이상한 상태로 중단됩니다. Ctrl- 를 사용하여이 상태에서 즉시 벗어날 수 있습니다 C.

  • 또한 을 (를) 사용 하거나 다른 구성 Tab을 확장 할 수 없습니다 .___!$

  • 일부 명령은 "정상적으로"실행될 때와 파이프에 연결될 때 다른 출력을 표시합니다. ( ls및 의 출력을 비교하십시오 ls | cat.)에 의해 트리거 된 명령 ___이이 중 하나 인 경우 예상과 다른 명령을 실행하게 될 수 있습니다.

  • 물론 마지막 줄 이외의 출력 줄로 무언가를 원한다면 도움이되지 않습니다.

나는 그 이름 ___이 논쟁이 아니라 명령 줄에 단어로 포함시키고 싶지 않은 것이기 때문에 이름을 선택했습니다 . 다른 이름을 선택할 수도 있지만 실수로 확장 될 수있는 것을 선택하지 않도록주의하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.