bash에서 마지막 출력 줄을 어떻게 실행할 수 있습니까?


12

bash에서 마지막 명령을 실행할 수 있다는 것을 알고 !!있지만 마지막 출력 줄을 어떻게 실행할 수 있습니까?

이 출력의 유스 케이스를 생각하고 있습니다.

The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

그러나 나는 그것을 어떻게 실행할 수 있는지 모른다. !!어쩌면 @@비슷한 비슷한 것을 생각하고 있습니까?


슈퍼 유저도이 질문을 가지고 있습니다.


1
그냥 복사해서 붙여 넣지 않겠습니까?
Pilot6

1
@Tim 프로그램 출력의 마지막 줄을 실행하는 방법을 원하지만이 특정 사용 사례의 경우 command_not_found_handle셸 함수 또는 실행되는 스크립트 를 변경하는 방법도 있습니다 (보통 그냥 /usr/lib/command-not-found). 패키지를 자동으로 설치하거나 패키지 이름이 어딘가에 저장되고 짧은 명령을 실행하여 설치할 수 있도록 대화식으로 프롬프트가 표시되도록 할 수 있다고 생각합니다. 그것은 당신이 여기에서 요청한 것과 충분히 다르므로 그것에 대해 별도의 질문을 게시하는 것을 고려할 수 있습니다.
Eliah Kagan


2
또한 관련이있을 수 : github.com/nvbn/thefuck 이 도구는 자동 (이름을 무시) 교정하는 자식 / 아파트 / 등 명령 :
bhathiya - 페레라

답변:


16

명령 $(!! |& tail -1)은 다음을 수행해야합니다.

$ git something
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

$ $(!! |& tail -1)
$(git something |& tail -1)
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
git-man liberror-perl

보시다시피 sudo apt-get install git명령이 실행 중입니다.

편집 : 세분화$(!! |& tail -1)

  • $()는 IS bash명령 치환 패턴

  • bash!!마지막으로 실행 된 명령으로 확장 됩니다

  • |&부분은 까다 롭습니다. 일반적으로 파이프 |는 왼쪽 명령의 STDOUT을 가져 와서 오른쪽의 명령에 STDIN으로 전달 |합니다.이 경우 이전 명령은 STDERR에 출력을 오류 메시지로 인쇄합니다. 따라서 |도움이되지 않으면 STDOUT 및 STDERR (또는 STDERR 만)을 오른쪽 명령으로 전달해야합니다. |&STDIN으로 STDOUT과 STDERR을 모두 오른쪽 명령에 전달합니다. 또는 STDERR 만 전달하는 것이 좋습니다.

    $(!! 2>&1 >/dev/null | tail -1)
  • tail -1평소와 같이 입력에서 마지막 줄을 인쇄합니다. 마지막 줄을 인쇄하는 대신 apt-get install명령 이 포함 된 줄을 인쇄하는 것보다 더 정확할 수 있습니다 .

    $(!! 2>&1 >/dev/null | grep 'apt-get install')

1
귀하의 접근 방식은 두 번째로 출력이 동일하다고 가정합니다. 일부 명령은 다음에 다른 출력을 생성 할 수 있으며,이 경우 출력의 마지막 행 실행이 실제로 수행 될 작업을 예측하기가 매우 어렵습니다.
kasperd

1
@kasperd 당신이 맞습니다 ..이 특정 예에 관한 한, 결과는 동일하게 유지되어야합니다.
heemayl

7

TL; DR : alias @@='$($(fc -ln -1) |& tail -1)'

Bash의 히스토리 상호 작용 기능 은 명령 의 출력 을 검사하는 메커니즘을 제공하지 않습니다 . 쉘은 저장하지 않으며 , 히스토리 확장은 특별히 실행 한 명령 또는 해당 명령의 일부를위한 것입니다.

이로써 마지막 명령을 다시 실행하고 stdoutstderr ( |&)를 명령 대체로 파이프하는 방법이 남습니다 . heemayl의 대답은 이것을 달성하지만 셸은 별칭을 확장하기 전에 히스토리 확장을 수행하기 때문에 별칭을 사용할 수 없습니다.

로 함수에서 활성화하더라도 쉘 함수에서 히스토리 확장을 작동시킬 수 없습니다 set -H. 나는 !!함수가 확장되지 않을 것이라고 의심 하고, 그것이 확장되었을 때 확장 될지 확실하지 않지만, 지금 그것이 확장되지 않았는지 정확히 모르겠습니다 .

따라서 아주 적은 타이핑으로이를 수행 할 수 있도록 설정하려면 히스토리 확장 대신 fc쉘 내장을 사용하여 히스토리에서 마지막 명령을 추출해야합니다. 이것은 기록 확장이 비활성화 된 경우에도 작동한다는 추가 이점이 있습니다.

에 나타낸 바와 같이 고든 데이비슨대답bash는 역사 확장을 포함하는 별칭 만들기 (에 슈퍼 사용자 ) $(fc -ln -1)을 시뮬레이션을 !!. heemayl의 명령!! 에 이것을 연결 하면 다음과 같습니다. $(!! |& tail -1)

$($(fc -ln -1) |& tail -1)

이것은 작동 $(!! |& tail -1)하지만 별칭 정의로 갈 수 있습니다.

alias @@='$($(fc -ln -1) |& tail -1)'

해당 정의를 실행하거나 새 셸 에 .bash_aliases넣거나 .bashrc새 셸을 시작한 @@후 마지막 명령에서 마지막 출력 줄을 실행하기 위해 간단히 입력 (또는 별명이라는 이름을 지정할 수 있음) 할 수 있습니다 .

ek@Io:~$ alias @@='$($(fc -ln -1) |& tail -1)'
ek@Io:~$ evolution
The program 'evolution' is currently not installed. You can install it by typing:
sudo apt-get install evolution
ek@Io:~$ @@
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  evolution-common evolution-data-server evolution-data-server-online-accounts
....

이것을 별도의 스크립트로 옮기는 옵션이 있습니까? fc가 아무것도 출력하지 않기 때문에 시도했지만 결국 실패했습니다 ... fc가 현재 쉘 세션의 기록을 따르므로 별도의 스크립트로 이동하면 빈 기록이있는 다른 세션이 열립니다. 물론 ... 스크립트에서 fc 행 위에있는 명령 중 하나가 실행되었습니다. 따라서 스크립트에 "컨텍스트"가 실행 된 bash 세션이라는 것을 알려주는 옵션이 있는지 궁금합니다. 예를 들어, #! / bin / bash에 대한 몇 가지 주장 또는 뭔가…
Exterminator13

Exterminator13 @ 당신은 당신이하는 별도의 스크립트를 의미하는 경우 실행 --like을 ./script하지 당신이 그 소스, .또는 source내장 - 미안 확실. 배쉬 쉘 출구에있는 파일을 추가하거나 실행할 때 history-a또는 -w(참조 help history). 그렇다면 여러 대화식 쉘의 명령이 인터리브됩니다 (실행 한 순서대로 나타남). 즉시 추가 할 수 있습니다. . 그러나 fc스크립트에서 작업 하려면 더 많은 것이 필요하다고 생각 합니다. 이에 대한 새로운 질문을 게시하는 것이 좋습니다. 그렇다면 여기에 링크를 달아주십시오.
Eliah Kagan

2

당신이 X에서 터미널 에뮬레이터를 사용하는 경우와 같은 gnome-terminal, konsole또는 xterm, 당신은 복사 및 붙여 넣기 같은 것을 위해 X 선택을 사용할 수 있습니다 :

기본 선택 사용

왼쪽 세 번 클릭 으로 실행할 전체 줄 을 선택 하십시오 .

그런 다음 가운데 버튼을 클릭 하여 명령 줄에 붙여 넣습니다 .

이것은 대부분의 터미널 에뮬레이터에서 작동합니다. 클립 보드를 건드리지 않고 기본 선택을 사용합니다. 별도입니다.
기술적으로 선택하여 한 번의 작업으로 복사 및 붙여 넣기를 결합했습니다.


1
@Tim 그게 사실이야-분명하게 해줄 게
Volker Siegel

1

Eliah Kagan이 언급했듯이 셸은 명령 출력을 저장하지 않습니다. 그러나, 출력의 마지막 명령의 마지막 줄을 얻을 수있는 방법이 명령을 다시 실행하지 않고 실행할 경우, 화면 .

다음 줄을 입력하십시오 ~/.screenrc.

register t "^a[k0y$ ^a]^a^L"
bind t process t

그런 다음 Ctrl+ at를 눌러 현재 프롬프트에 이전 줄을 삽입 할 수 있습니다 . Enter 키를 자동으로 누르는 것도 가능하지만 실행하기 전에 확인하고 Enter 키를 누르는 것이 좋습니다.

작동 방식 :

  • register t이라는 이름의 버퍼에 문자열을 등록합니다 t. 그 뒤에 나오는 문자열은 키 순서입니다.
  • bind t키에 바인딩합니다 t(즉 , Ctrl+를 사용하여 실행 at) . process t라는 버퍼의 내용을 평가하는 것을 의미합니다 t.
  • 시퀀스 자체는 다음을 의미합니다.
    • ^a[(= Ctrla[) : 복사 모드로 들어갑니다
    • k한 줄 위로 0이동, 줄 시작으로 이동, 줄 y$끝까지 복사, (공백) 명령 완료
    • ^a](= Ctrla]) : 복사 한 내용 붙여 넣기
    • ^a^L(= CtrlaCtrlL) 화면을 새로 고칩니다 (그렇지 않으면 직접 입력하지 않았기 때문에 붙여 넣은 내용이 표시되지 않습니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.