Programing

Bash를 사용하여 마지막 명령의 출력을 변수로 자동 캡처합니까?

crosscheck 2020. 6. 25. 08:14
반응형

Bash를 사용하여 마지막 명령의 출력을 변수로 자동 캡처합니까?


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

$ 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/x솔루션을 처음 시도 잊지 마십시오
  • 마지막 명령의 종료 코드가 성공한 경우에만 결과가 저장됩니다

이것은 정말 해킹 된 솔루션이지만 대부분 시간이 지남에 따라 작동합니다. 테스트하는 동안 ^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

나는 이것을 자동으로 수행하는 변수를 모른다 . 결과를 복사하여 붙여 넣기하는 것 외에 다른 작업을 수행하려면 방금 수행 한 모든 작업을 다시 실행할 수 있습니다.

vim $(!!)

!!'이전 명령'을 의미하는 히스토리 확장은 어디에 있습니까 ?

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


배쉬는 못생긴 언어입니다. 예, 출력을 변수에 할당 할 수 있습니다

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

그러나 findBash 변수에 할당 할 때 자동으로 수정되므로 캐리지 리턴 또는 줄 바꿈과 같이 하나의 결과 만 반환하고 그 결과에 "홀수"문자가없는 것이 가장 좋습니다 .

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

그것은 직접 파일을 예와 함께 행동하는 것이 낫다 find'들 -execdir(설명서를 참조).

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

또는

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

이를 수행하는 방법은 여러 가지가 있습니다. 한 가지 방법은 v=$(command)명령 출력을에 할당하는 것 v입니다. 예를 들면 다음과 같습니다.

v=$(date)
echo $v

역 따옴표도 사용할 수 있습니다.

v=`date`
echo $v

에서 배쉬 초보자 가이드 ,

이전 스타일의 역 따옴표로 대체 된 형식을 사용하는 경우 백 슬래시는 "$", "`"또는 "\"가 뒤에 나오는 경우를 제외하고 문자 그대로의 의미를 유지합니다. 백 슬래시 앞에 있지 않은 첫 번째 백틱은 명령 대체를 종료합니다. "$ (COMMAND)"양식을 사용할 때 괄호 안의 모든 문자가 명령을 구성합니다. 아무것도 특별하게 취급되지 않습니다.

편집 : 질문에서 편집 한 후에 이것은 OP가 찾고있는 것이 아닌 것 같습니다. 내가 아는 한, $_마지막 명령의 출력 과 같은 특별한 변수는 없습니다 .


아주 쉽습니다. 역 따옴표를 사용하십시오.

var=`find . -name foo.txt`

그리고 나중에 언제든지 사용할 수 있습니다

echo $var
mv $var /somewhere

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

#!/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

Disclamers :

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

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

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

그래, 지금 우리에게 많은 가능성을 제공합니다 :)으로 나를 위해, 나는 간단한 별칭을 설정 : alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1"지금 때마다 나는 내가 간단하게 사용하는 마지막 줄에 액세스해야 $(L)그것을 얻을 수 있습니다.

이것은 프로그램이 사용하는 출력 스트림 (stdin 또는 stderr), 인쇄 방법 (ncurses 등) 및 프로그램의 종료 코드와 무관합니다. 데이터 만 표시하면됩니다.


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'

방금 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

업데이트 : 대체 제안 익명 사용자 echo에 의해 printf '%s\n'어떤는 같은 프로세스 옵션을하지 않는 장점이있다 -e캡처 한 텍스트를. 따라서 그러한 특성을 기대하거나 경험한다면이 제안을 고려하십시오. 다른 옵션은 cat <<<$grab대신 사용하는 것입니다.


"이후의 명령에서 마지막으로 실행 된 명령의 결과를 사용할 수 있기를 원합니다"라고 말하면 -찾기뿐만 아니라 모든 명령의 결과를 의미한다고 가정합니다.

그렇다면 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/{}

This command deals with multiple files and works like a charm even if the path and/or filename contains space(s).

Notice the mv {} /some/new/location/{} part of the command. This command is build and executed for each line printed by earlier command. Here the line printed by earlier command is replaced in place of {}.

Excerpt from man page of xargs:

xargs - build and execute command lines from standard input

For more detail see man page: man xargs


Capture the output with backticks:

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

I usually do what the others here have suggested ... without the assignment:

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

You can get fancier if you like:

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

If all you want is to rerun your last command and get the output, a simple bash variable would work:

LAST=`!!`

So then you can run your command on the output with:

yourCommand $LAST

This will spawn a new process and rerun your command, then give you the output. It sounds like what you would really like would be a bash history file for command output. This means you will need to capture the output that bash sends to your terminal. You could write something to watch the /dev or /proc necessary, but that's messy. You could also just create a "special pipe" between your term and bash with a tee command in the middle which redirects to your output file.

But both of those are kind of hacky solutions. I think the best thing would be terminator which is a more modern terminal with output logging. Just check your log file for the results of the last command. A bash variable similar to the above would make this even simpler.


Here's one way to do it after you've executed your command and decided that you want to store the result in a variable:

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

Or if you know ahead of time that you'll want the result in a variable, you can use backticks:

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

As an alternative to the existing answers: Use while if your file names can contain blank spaces like this:

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

As I wrote, the difference is only relevant if you have to expect blanks in the file names.

NB: the only built-in stuff is not about the output but about the status of the last command.


you can use !!:1. Example:

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

I had a similar need, in which I wanted to use the output of last command into the next one. Much like a | (pipe). eg

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

to something like -

$ which gradle |: ls -altr {}

Solution : Created this custom pipe. Really simple, using xargs -

$ alias :='xargs -I{}'

Basically nothing by creating a short hand for xargs, it works like charm, and is really handy. I just add the alias in .bash_profile file.


It can be done using the magic of file descriptors and the lastpipe shell option.

It has to be done with a script - the "lastpipe" option will not work in interactive mode.

Here's the script I've tested with:

$ cat shorttest.sh 
#!/bin/bash
shopt -s lastpipe

exit_tests() {
    EXITMSG="$(cat /proc/self/fd/0)"
}

ls /bloop 2>&1 | exit_tests

echo "My output is \"$EXITMSG\""


$ bash shorttest.sh 
My output is "ls: cannot access '/bloop': No such file or directory"

What I'm doing here is:

  1. setting the shell option shopt -s lastpipe. It will not work without this as you will lose the file descriptor.

  2. making sure my stderr also gets captured with 2>&1

  3. piping the output into a function so that the stdin file descriptor can be referenced.

  4. setting the variable by getting the contents of the /proc/self/fd/0 file descriptor, which is stdin.

I'm using this for capturing errors in a script so if there is a problem with a command I can stop processing the script and exit right away.

shopt -s lastpipe

exit_tests() {
    MYSTUFF="$(cat /proc/self/fd/0)"
    BADLINE=$BASH_LINENO
}

error_msg () {
    echo -e "$0: line $BADLINE\n\t $MYSTUFF"
    exit 1
}

ls /bloop 2>&1 | exit_tests ; [[ "${PIPESTATUS[0]}" == "0" ]] || error_msg

In this way I can add 2>&1 | exit_tests ; [[ "${PIPESTATUS[0]}" == "0" ]] || error_msg behind every command I care to check on.

Now you can enjoy your output!


This is not strictly a bash solution but you can use piping with sed to get the last row of previous commands output.

First lets see what i have in folder "a"

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

Then, your example with ls and cd would turn to sed & piping into something like this:

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

So, the actual magic happens with sed, you pipe what ever output of what ever command into sed and sed prints the last row which you can use as parameter with back ticks. Or you can combine that to xargs also. ("man xargs" in shell is your friend)


The shell doesn't have perl-like special symbols that store the echo result of the last command.

Learn to use the pipe symbol with awk.

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

In the example above you could do:

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

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

is yet another way, albeit dirty.

참고URL : https://stackoverflow.com/questions/5955577/automatically-capture-output-of-last-command-into-a-variable-using-bash

반응형