[Linux] bash - 마지막으로 실행 한 명령의 출력을 변수에 자동 캡처합니다.


Answers

이것은 정말 해킹 된 솔루션이지만, 대부분 시간이 걸리는 것으로 보입니다. 테스트하는 동안 커맨드 라인에서 ^ C 를 사용할 때 때로는 제대로 작동하지 않는다고 지적했습니다.

이 해킹은 대화 형 모드의 해킹 일 뿐이며 누구에게도 추천하지 않는다고 확신합니다. 백그라운드 명령은 정상보다 덜 정의 된 동작을 일으킬 수 있습니다. 다른 대답은 프로그래밍 방식으로 결과를 얻는 더 좋은 방법입니다.

즉, "해결책"이 있습니다.

PROMPT_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)'

이 bash 환경 변수를 설정하고 원하는대로 명령을 실행하십시오. $LAST 에는 일반적으로 찾고있는 결과가 있습니다.

startide seth> fortune
Courtship to marriage, as a very witty prologue to a very dull play.
                -- William Congreve
startide seth> echo "$LAST"
Courtship to marriage, as a very witty prologue to a very dull play.
                -- William Congreve
Question

후속 명령에서 마지막으로 실행 한 명령의 결과를 사용할 수 있기를 원합니다. 예를 들어,

$ find . -name foo.txt
./home/user/some/directory/foo.txt

이제 내가 편집기에서 파일을 열거 나 삭제할 수 있기를 원한다고 가정 해 봅시다.

mv <some-variable-that-contains-the-result> /some/new/location

내가 어떻게 해? 어쩌면 일부 bash 변수를 사용하고 있을까요?

최신 정보:

명확히하기 위해 나는 물건을 수동으로 할당하고 싶지 않다. 내가 쓴 것은 내장 된 bash 변수와 같은 것이다.

ls /tmp
cd $_

$_ 는 이전 명령의 마지막 인수를 보유합니다. 나는 비슷한 것을 원하지만 마지막 명령의 출력을 원한다.

최종 업데이트 :

세스의 대답은 아주 잘 풀렸다. 염두에 두어야 할 몇 가지 사항 :

  • 처음으로 솔루션을 시도 할 때 touch /tmp/xtouch /tmp/x 하는 것을 잊지 마십시오.
  • 마지막 명령의 종료 코드가 성공한 경우에만 결과가 저장됩니다.



find . -name foo.txt 1> tmpfile && mv `cat tmpfile` /path/to/some/dir/

비록 더러 웠지만 또 다른 방법입니다.




쉘을 스크립트를 포함하는 솔루션을 해킹 할 수 있다고 생각합니다.

#!/bin/sh
bash | tee /var/log/bash.out.log

그런 다음 $PROMPT_COMMAND 를 구분 기호를 출력하도록 설정하면, 해당 로그의 마지막 청크를 가져 오는 도우미 함수 (예 : _ )를 작성할 수 있으므로 다음과 같이 사용할 수 있습니다.

% find lots*of*files
...
% echo "$(_)"
... # same output, but doesn't run the command again



이것은 엄격하게 bash 솔루션이 아니지만 sed와 함께 파이핑을 사용하여 이전 명령 출력의 마지막 행을 가져올 수 있습니다.

먼저 폴더 "a"에있는 것을 볼 수 있습니다.

rasjani@helruo-dhcp022206::~$ find a
a
a/foo
a/bar
a/bat
a/baz
rasjani@helruo-dhcp022206::~$ 

그렇다면 ls와 cd를 사용한 예제는 sed와 piping을 다음과 같이 바꿀 것입니다 :

rasjani@helruo-dhcp022206::~$ cd `find a |sed '$!d'`
rasjani@helruo-dhcp022206::~/a/baz$ pwd
/home/rasjani/a/baz
rasjani@helruo-dhcp022206::~/a/baz$

따라서 실제 마법은 sed와 함께 발생합니다. sed와 sed에 명령을 내린 결과는 백 틱이있는 매개 변수로 사용할 수있는 마지막 행을 인쇄합니다. 또는 이것을 xargs와 결합 할 수도 있습니다. (쉘에서 "man xargs"는 친구입니다)




마지막 명령을 다시 실행하여 출력을 얻고 싶다면 간단한 bash 변수가 작동합니다.

LAST=`!!`

그러면 다음 명령을 사용하여 출력에 명령을 실행할 수 있습니다.

yourCommand $LAST

이것은 새로운 프로세스를 생성하고 명령을 다시 실행 한 다음 결과를 제공합니다. 명령 출력을위한 bash 히스토리 파일이 정말로 마음에들 것 같습니다. 즉, bash가 터미널로 보내는 출력을 캡처해야합니다. / dev 또는 / proc 필요한 것을보기 위해 무언가를 쓸 수도 있지만, 그것은 지저분합니다. 중간에 tee 명령을 사용하여 용어와 bash 사이에 "특수 파이프"를 만들어 출력 파일로 리디렉션 할 수도 있습니다.

그러나 두 가지 모두 해킹 된 솔루션입니다. 가장 좋은 방법은 출력 로깅이있는 최신 터미널 인 terminator 라고 생각합니다. 로그 파일에서 마지막 명령의 결과를 확인하십시오. 위와 비슷한 bash 변수를 사용하면이 작업이 훨씬 간단 해집니다.




나는 비슷한 커맨드의 출력을 다음 커맨드에 사용하고 싶었습니다. 많이 좋아요. (파이프). 예

$ which gradle 
/usr/bin/gradle
$ ls -alrt /usr/bin/gradle

~에 무언가에 -

$ which gradle |: ls -altr {}

솔루션 :이 사용자 정의 파이프를 생성했습니다. xargs를 사용하여 정말 간단합니다.

$ alias :='xargs -I{}'

기본적으로 xargs에 대한 짧은 손을 만들어 아무것도, 그것은 매력처럼 작동하고 정말 편리합니다. 방금 .bash_profile 파일에 별명을 추가합니다.




"후속 명령에서 마지막으로 실행 된 명령의 결과를 사용할 수 있기를 원합니다."라고 말하면 , 그냥 찾는 것이 아니라 모든 명령의 결과를 의미합니다.

thats 경우 - xargs 는 당신이 찾고있는 것입니다.

find . -name foo.txt -print0 | xargs -0 -I{} mv {} /some/new/location/{}

또는 출력을 먼저 보려면 관심이있는 경우 :

find . -name foo.txt -print0

!! | xargs -0 -I{} mv {} /some/new/location/{}

이 명령은 경로 및 / 또는 파일 이름에 공백이있는 경우에도 여러 파일을 처리하고 매력과 같이 작동합니다.

명령의 mv {} / some / new / location / {} 부분에 주목하십시오. 이 명령은 이전 명령으로 인쇄 된 각 행에 대해 빌드되고 실행됩니다. 여기서 이전 명령에 의해 인쇄 된 행이 {} 대신 대체됩니다.

xargs의 맨 페이지에서 발췌 :

xargs - 표준 입력에서 명령 행을 빌드하고 실행합니다.

자세한 내용은 man 페이지를 참조하십시오 : man xargs




방금 여기 bash 함수를 제안에서 제외했다.

grab() {     
  grab=$("$@")
  echo $grab
}

그럼, 당신은 단지 :

> grab date
Do 16. Feb 13:05:04 CET 2012
> echo $grab
Do 16. Feb 13:05:04 CET 2012

업데이트 : 익명의 사용자가 printf '%s\n' 의해 대체 할 것을 제안했는데 그래 브 텍스트에서 -e 와 같은 옵션을 처리하지 않는다는 이점이 있습니다. 따라서 이러한 특성을 기대하거나 경험한다면이 제안을 고려하십시오. 또 다른 옵션은 cat <<<$grab 대신 사용하는 것입니다.




그것은 아주 쉽습니다. 역 인용 부호 사용 :

var=`find . -name foo.txt`

그런 다음 언제든지 사용할 수 있습니다.

echo $var
mv $var /somewhere



Disclamers :

  • 이 답변은 늦은 반년입니다 : D
  • 나는 무거운 tmux 사용자이다.
  • 이 작업을하려면 tmux에서 쉘을 실행해야합니다.

tmux에서 대화 형 쉘을 실행할 때 터미널에 현재 표시된 데이터에 쉽게 액세스 할 수 있습니다. 흥미로운 명령을 살펴 보겠습니다.

  • tmux capture-pane :이 명령은 표시된 데이터를 tmux의 내부 버퍼 중 하나로 복사합니다. 현재 표시되지 않는 기록을 복사 할 수 있지만 지금은 관심이 없습니다.
  • tmux list-buffers : 캡처 된 버퍼에 대한 정보를 표시합니다. 가장 최신의 번호는 0입니다.
  • tmux show-buffer -b (buffer num) : 이것은 주어진 버퍼의 내용을 터미널에 출력한다.
  • tmux paste-buffer -b (버퍼 num) : 주어진 버퍼의 내용을 입력으로 붙여 넣습니다 .

그래, 지금 우리에게 많은 가능성을 제공한다. 나는 alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1" 이라는 간단한 별칭을 설정했다 alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1" 마지막 줄에 액세스해야 할 때마다 $(L) 을 사용합니다.

이는 프로그램이 사용하는 출력 스트림 (stdin 또는 stderr), 인쇄 메소드 (ncurses 등) 및 프로그램 종료 코드와는 독립적입니다. 데이터를 표시하면됩니다.




당신은 사용할 수 있습니다 !! : 1. 예:

~]$ ls *.~
class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~ 

~]$ rm !!:1
rm class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~ 


~]$ ls file_to_remove1 file_to_remove2
file_to_remove1 file_to_remove2

~]$ rm !!:1
rm file_to_remove1

~]$ rm !!:2
rm file_to_remove2



셸에는 마지막 명령의 에코 결과를 저장하는 펄과 같은 특수 기호가 없습니다.

awk로 파이프 기호를 사용하는 법을 배웁니다.

find . | awk '{ print "FILE:" $0 }'

위의 예에서 다음을 할 수 있습니다.

find . -name "foo.txt" | awk '{ print "mv "$0" ~/bar/" | "sh" }'



나는 보통 여기서 다른 사람들이 제안한 바를하지 않고 ... 과제없이 :

$find . -iname '*.cpp' -print
./foo.cpp
./bar.cpp
$vi `!!`
2 files to edit

당신이 좋아하면 더 좋아할 수 있습니다 :

$grep -R "some variable" * | grep -v tags
./foo/bar/xxx
./bar/foo/yyy
$vi `!!`



기존 답변의 대안 : 파일 이름에 다음과 같이 공백이 포함될 수있는 while 사용 :

find . -name foo.txt | while IFS= read -r var; do
  echo "$var"
done

필자가 말했듯이 파일 이름에 공백을 넣어야 만하는 경우에만 차이가 있습니다.

주의 : 내장 된 유일한 물건은 출력에 관한 것이 아니라 마지막 명령의 상태에 관한 것입니다.




이를 수행하는 방법은 여러 가지가 있습니다. 한 가지 방법은 v=$(command) 를 사용하여 v=$(command) 의 명령 출력을 할당하는 것입니다. 예 :

v=$(date)
echo $v

그리고 역 인용 부호도 사용할 수 있습니다.

v=`date`
echo $v

Bash 초보자 가이드에서 ,

이전 스타일의 역순 대체 형식을 사용하는 경우 백 슬래시는 "$", ""또는 "\"다음에 오는 경우를 제외하고는 문자 그대로의 의미를 유지합니다. 백 슬래시 앞에없는 첫 번째 백틱은 명령 대체를 종료합니다. "$ (COMMAND)"형식을 사용할 때 괄호 사이의 모든 문자가 명령을 구성합니다. 아무도 특별하게 대우받지 않는다.

수정 : 질문에 편집 후, 이것이 OP가 찾고있는 것 같지 않습니다. 지금까지 내가 아는 한, 마지막 명령 출력을 위해 $_ 와 같은 특별한 변수는 없다.




나는 이것을 자동으로 하는 변수를 모른다. 결과를 복사하여 붙이기 만하면되는 것을 제외하고 방금 한 일을 다시 실행할 수 있습니다.

vim $(!!)

어디 !! 역사 확장은 '이전 명령'을 의미합니다.

적절한 인수 구문 분석을 방해 할 수있는 공백이나 다른 문자가 포함 된 단일 파일 이름이있을 것으로 예상되는 경우 결과 ( vim "$(!!)" )를 인용하십시오. 따옴표를 사용하지 않으면 공백이나 다른 쉘 구문 분석 토큰을 ​​포함하지 않는 한 여러 파일을 한 번에 열 수 있습니다.




명령을 실행 한 후 결과를 변수에 저장하기로 결정한 후이를 수행하는 한 가지 방법이 있습니다.

$ find . -name foo.txt
./home/user/some/directory/foo.txt
$ OUTPUT=`!!`
$ echo $OUTPUT
./home/user/some/directory/foo.txt
$ mv $OUTPUT somewhere/else/

또는 미리 변수에 결과를 원한다면 backticks를 사용할 수 있습니다.

$ OUTPUT=`find . -name foo.txt`
$ echo $OUTPUT
./home/user/some/directory/foo.txt



백틱으로 출력을 캡처하십시오.

output=`program arguments`
echo $output
emacs $output



Bash는 일종의 추악한 언어입니다. 예, 출력을 변수에 지정할 수 있습니다.

MY_VAR="$(find -name foo.txt)"
echo "$MY_VAR"

하지만 하나의 결과 만 반환하고 Bash 변수에 할당 될 때 자동으로 수정되므로 캐리지 리턴이나 줄 바꿈과 같은 "이상한"문자가없는 결과가 반환되는 것이 가장 바람직합니다.

그러나 사용할 때 변수를 올바르게 인용하는 것이 좋습니다.

예를 들어 find-execdir (매뉴얼 참조)과 같이 파일을 직접 조작하는 것이 좋습니다.

find -name foo.txt -execdir vim '{}' ';'

또는

find -name foo.txt -execdir rename 's/\.txt$/.xml/' '{}' ';'



bash 프로파일에 다음 별명을 설정할 수 있습니다.

alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))'

그런 다음 임의의 명령 다음에 's'를 입력하여 결과를 쉘 변수 'it'에 저장할 수 있습니다.

따라서 예제 사용법은 다음과 같습니다.

$ which python
/usr/bin/python
$ s
$ file $it
/usr/bin/python: symbolic link to `python2.6'