codememo

Bash의 마지막 명령어 출력 재사용

tipmemo 2023. 4. 18. 22:45
반응형

Bash의 마지막 명령어 출력 재사용

Bash 명 bash bash bash e e e e e? 를음음음음음음음음음음 to to to to to to to to to to $?종료 상태가 아닌 출력을 캡처합니다.

다음과 같은 방법으로 출력을 변수에 할당할 수 있습니다.

output=$(command)

하지만 그건 타이핑이 더...

하시면 됩니다.$(!!)마지막 명령어의 출력을 재계산(재사용하지 않음)합니다.

!!는 그 자체로 마지막 명령을 실행합니다.

$ echo pierre
pierre
$ echo my name is $(!!)
echo my name is $(echo pierre)
my name is pierre

대답은 '아니오'입니다.Bash는 메모리 상의 파라미터나 블록에 출력을 할당하지 않습니다.또한 허용된 인터페이스 조작에 의해서만 Bash에 액세스할 수 있습니다.Bash의 개인 데이터는 해킹하지 않으면 접근할 수 없습니다.

매우 심플한 솔루션

내가 몇 년 동안 써온 거야

에 ).bashrc ★★★★★★★★★★★★★★★★★」.bash_profile)

# capture the output of a command so it can be retrieved with ret
cap () { tee /tmp/capture.out; }

# return the output of the most recent command that was captured by cap
ret () { cat /tmp/capture.out; }

사용.

$ find . -name 'filename' | cap
/path/to/filename

$ ret
/path/to/filename

는 원래 ㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇ.| cap아! 저속 텍스트 했을 때 든지 " "로 수 .ret.

mac에서 변수에 쓰는 대신 클립보드에 출력을 저장하는 것이 문제가 되지 않는 경우 pbcopy와 pbpaste를 회피책으로 사용할 수 있습니다.

예를 들어, 파일을 검색하여 다른 파일로 내용을 구분하는 대신 다음을 수행합니다.

$ find app -name 'one.php' 
/var/bar/app/one.php

$ diff /var/bar/app/one.php /var/bar/two.php

다음과 같이 할 수 있습니다.

$ find app -name 'one.php' | pbcopy
$ diff $(pbpaste) /var/bar/two.php

" " "/var/bar/app/one.php첫 번째 명령을 실행할 때 클립보드에 있습니다.

그나저나, pb inpbcopy ★★★★★★★★★★★★★★★★★」pbpaste클립보드의 동의어인 페이스트보드를 나타냅니다.

그 중는 '아예'를 입니다.trap DEBUG:

f() { bash -c "$BASH_COMMAND" >& /tmp/out.log; }
trap 'f' DEBUG

및 은 stdout stderr에서 사용할 수 ./tmp/out.log

, 2회 하는 것이 를 2회 경우는 입니다./tmp/out.log을 사용하다아마 이런 행동을 막을 수 있는 방법이 있을 거예요.

anubhava의 답변에서 영감을 얻어 각 명령어를 두 번 실행하므로 실제로는 받아들일 수 없다고 생각합니다.

save_output() { 
   exec 1>&3 
   { [ -f /tmp/current ] && mv /tmp/current /tmp/last; }
   exec > >(tee /tmp/current)
}

exec 3>&1
trap save_output DEBUG

이렇게 하면 last 명령어의 출력은 /tmp/last이며 명령어는 두 번 호출되지 않습니다.

그래, 왜 매번 여분의 줄을 쳐야 하지? 동의해.명령에서 반환된 를 파이프라인에 의한 입력으로 리다이렉트 할 수 있지만 인쇄 출력을 입력(1>&0)으로 리다이렉트 하는 것은 적어도 여러 줄 출력에서는 할 수 없습니다.또한 동일한 파일에 대해 함수를 여러 번 다시 쓰는 것도 원하지 않을 것입니다.그럼 다른 걸 해보죠

간단한 회피책은 printf 함수를 사용하여 변수에 값을 저장하는 것입니다.

printf -v myoutput "`cmd`"

예를 들어

printf -v var "`echo ok;
  echo fine;
  echo thankyou`"
echo "$var" # don't forget the backquotes and quotes in either command.

커스터마이즈 가능한 또 다른 범용 솔루션(나 자신이 사용)에서는 원하는 명령어를 한 번만 실행하여 어레이 변수에서 한 줄씩 여러 줄 출력할 수 있습니다.

파일을 내보내지 않고 로컬에서만 사용하려는 경우 터미널에서 함수 선언을 설정할 수 있습니다. You have to add the function in 에 기능을 추가해야 합니다.~/.bashrc file or in 줄서기 또는 줄서기 또는 줄서기~/.profile파일. 둘째 경우 일을 사용하도록 설정해야 합니다. 두 번째 경우,Run command as login shell부에서Edit>Preferences>yourProfile>Command.

다음과 같이 간단한 함수를 만듭니다.

get_prev() # preferably pass the commands in quotes. Single commands might still work without.
{
    # option 1: create an executable with the command(s) and run it
    #echo $* > /tmp/exe
    #bash /tmp/exe > /tmp/out
    
    # option 2: if your command is single command (no-pipe, no semi-colons), still it may not run correct in some exceptions.
    #echo `"$*"` > /tmp/out
    
    # option 3: (I actually used below)
    eval "$*" > /tmp/out # or simply "$*" > /tmp/out
    
    # return the command(s) outputs line by line
    IFS=$(echo -en "\n\b")
    arr=()
    exec 3</tmp/out
    while read -u 3 -r line
    do
        arr+=($line)
        echo $line
    done
    exec 3<&-
}

그래서 1에 있는 것은 임시 파일 션 1 1 령 체 시 일에 1 was so did what다 option니 command인 in file we the습파임했 to a전쇄로를명 print어/tmp/exe and run it and save the output to another file 실행 후 출력을 다른 파일에 저장합니다./tmp/out 이 글의 ./tmp/out아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 네.실행할 실행 파일에 쓰지 않고 명령어를 그대로 내보낸다는 점만 제외하면 옵션2와 3과 비슷합니다.

기본 스크립트:

#run your command:

cmd="echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"
get_prev $cmd

#or simply
get_prev "echo hey ya; echo hey hi; printf `expr 10 + 10`'\n' ; printf $((10 + 20))'\n'"

하므로 bash는 이전 범위를 벗어나도 합니다.arr에서 get_prev메인 스크립트의 기능 외부에서도 기능에 액세스 할 수 있습니다.

#get previous command outputs in arr
for((i=0; i<${#arr[@]}; i++))
do
    echo ${arr[i]}
done
#if you're sure that your output won't have escape sequences you bother about, you may simply print the array
printf "${arr[*]}\n"

편집:

I use the following code in my implementation:
get_prev()
{
    usage()
    {
        echo "Usage: alphabet [ -h | --help ]
        [ -s | --sep SEP ]
        [ -v | --var VAR ] \"command\""
    }
    
    ARGS=$(getopt -a -n alphabet -o hs:v: --long help,sep:,var: -- "$@")
    if [ $? -ne 0 ]; then usage; return 2; fi
    eval set -- $ARGS
    
    local var="arr"
    IFS=$(echo -en '\n\b')
    for arg in $*
    do
        case $arg in
            -h|--help)
                usage
                echo " -h, --help : opens this help"
                echo " -s, --sep  : specify the separator, newline by default"
                echo " -v, --var  : variable name to put result into, arr by default"
                echo "  command   : command to execute. Enclose in quotes if multiple lines or pipelines are used."
                shift
                return 0
                ;;
            -s|--sep)
                shift
                IFS=$(echo -en $1)
                shift
                ;;
            -v|--var)
                shift
                var=$1
                shift
                ;;
            -|--)
                shift
                ;;
            *)
                cmd=$option
                ;;
        esac
    done
    if [ ${#} -eq 0 ]; then usage; return 1; fi
    
    ERROR=$( { eval "$*" > /tmp/out; } 2>&1 )
    if [ $ERROR ]; then echo $ERROR; return 1; fi
    
    local a=()
    exec 3</tmp/out
    while read -u 3 -r line
    do
        a+=($line)
    done
    exec 3<&-
    
    eval $var=\(\${a[@]}\)
    print_arr $var # comment this to suppress output
}

print()
{
    eval echo \${$1[@]}
}

print_arr()
{
    eval printf "%s\\\n" "\${$1[@]}"
}

다중/파이프라인/두 명령어의 공백으로 구분된 출력을 줄 구분된 출력으로 인쇄하기 위해 이 기능을 사용해 왔습니다.

get_prev -s " " -v myarr "cmd1 | cmd2; cmd3 | cmd4"

예를 들어 다음과 같습니다.

get_prev -s ' ' -v myarr whereis python # or "whereis python"
# can also be achieved (in this case) by
whereis python | tr ' ' '\n'

, 이제tr는 다른합니다.

echo $PATH | tr ':' '\n'

그러나 다중/피핑된 명령의 경우...이제 아시겠죠?:)

- 히만슈

Konsolebox가 말한 것처럼, 당신은 스스로 bash를 해킹해야 합니다.여기 이것을 어떻게 달성할 수 있는지에 대한 꽤 좋은 예가 있다.stderred 저장소(실제로 stdout을 색칠하기 위한 의미)는 빌드 방법에 대한 지침을 제공합니다.

해 보았다:하다: 새로운 파일 기술자를 정의하다.bashrc

exec 41>/tmp/my_console_log

는 임의)및('번호')stderred.c따라서 내용도 fd 41에 쓰이게 됩니다.동작은 했지만, NUL 바이트의 부하와 이상한 포맷이 포함되어 있습니다.기본적으로 바이너리 데이터이기 때문에 읽을 수 없습니다.C에 대한 이해가 좋은 사람이 시도해 볼 수 있을 것 같습니다.

이 경우 마지막 인쇄된 라인을 얻기 위해 필요한 모든 것은 다음과 같습니다.tail -n 1 [logfile]

이 답변이 필요한 이유를 정확히 알 수 없기 때문에 이 답변은 관련이 없을 수 있습니다.할 수 .netstat >> output.txt하지만 그걸 찾으시는 건 아닌 것 같은데요

물론 프로그래밍 옵션도 있습니다.명령어를 실행한 후에 위의 텍스트파일을 읽어 변수와 관련짓는 프로그램만 있으면 됩니다.또, 내가 선택한 언어인 루비에서는, 「backticks」를 사용해 커맨드 아웃풋의 변수를 작성할 수 있습니다.

output = `ls`                       #(this is a comment) create variable out of command

if output.include? "Downloads"      #if statement to see if command includes 'Downloads' folder
print "there appears to be a folder named downloads in this directory."
else
print "there is no directory called downloads in this file."
end

한다: ".rb"ruby file.rb명령어를 사용하여 변수를 생성하여 조작할 수 있습니다.

이전 명령어를 재계산하지 않으려면 현재 터미널 버퍼를 스캔하여 마지막 명령어의 -supplied 출력을 추측하고 클립보드에 복사한 후 단말기에 입력하는 매크로를 만들 수 있습니다.

18에서 1행의 Ubuntu 18.04로 )에할 수 .gnome-terminal를 참조해 주세요.

합니다.xdootool,xclip,ruby

»gnome-terminalPreferences -> Shortcuts -> Select all로 설정합니다.Ctrl+shift+a.

다음 루비 스크립트를 만듭니다.

cat >${HOME}/parse.rb <<EOF
#!/usr/bin/ruby
stdin = STDIN.read
d = stdin.split(/\n/)
e = d.reverse
f = e.drop_while { |item| item == "" }
g = f.drop_while { |item| item.start_with? "${USER}@" }
h = g[0] 
print h
EOF

키보드 설정에서 다음 키보드숏컷을 추가합니다.

bash -c '/bin/sleep 0.3 ; xdotool key ctrl+shift+a ; xdotool key ctrl+shift+c ; ( (xclip -out | ${HOME}/parse.rb ) > /tmp/clipboard ) ; (cat /tmp/clipboard | xclip -sel clip ) ; xdotool key ctrl+shift+v '

위의 바로 가기:

  • 현재 터미널 버퍼를 클립보드에 복사합니다.
  • 마지막 명령어의 출력을 추출합니다(1행만).
  • 현재 단말기에 입력합니다.

지금 당장 실행하려고 할 시간이 없다는 생각이 나요.

하지만 다음과 같은 작업을 수행하면 어떻게 됩니까?

$ MY_HISTORY_FILE = `get_temp_filename`
$ MY_HISTORY_FILE=$MY_HISTORY_FILE bash -i 2>&1 | tee $MY_HISTORY_FILE
$ some_command
$ cat $MY_HISTORY_FILE
$ # ^You'll want to filter that down in practice!

IO 버퍼링에 문제가 있을 수 있습니다.또한 파일이 너무 커질 수 있습니다.누군가는 이 문제들에 대한 해결책을 생각해내야 할 것이다.

스크립트 명령어를 사용하면 도움이 될 것 같습니다.뭐랄까...

  1. 스크립트 -c bash -qf fifo_pid

  2. 해석 후 bash 기능을 사용하여 설정.

중단 없는 명령어 데모만:http://asciinema.org/a/395092

명령어를 , 「해킹」을 .script하여 화면 세션 합니다.bash-linux에서 bashrc로 이동합니다.

현재 답변 중 어느 것도 실제 해결책이 아닙니다. 요점을 놓쳤기 때문입니다.다음은 명령어의 출력을 읽는 방법입니다.

  1. 검사한 후에요
  2. 그들을 두 번 처형하지 않으면 대혼란을 일으킬 수 있다.
  3. SSD를 모두 사용하는 임시 파일이 없습니다.

올바른 질문

먼저 셸이 출력을 전혀 인식하지 못한다는 것을 깨달아야 합니다.그것에 초점을 맞춘 답변은 모두 파기할 수 있습니다.
stdin, stdout r stderr 3 의 、 stderr 3 가 、 stderr 가 3 가 。그것들은 또한 다음과 같이 이용할 수 있다./proc/self/[0-2] ★★★★★★★★★★★★★★★★★」/dev/pts/[0-2].
이것들은 의사 터미널 슬레이브입니다.의사 터미널은 기본적으로 마스터와 슬레이브 엔드를 가진 명명된 파이프일 뿐입니다.마스터 엔드는 프로세스가 /dev/pts/ptmx를 열어서 얻는 파일 기술자에 불과합니다. (이것은 pseudo-termunal master muxer의 약자)…과거에는 이러한 파일들이 /dev/ 어딘가에 따로 있었습니다.진정한 Unix에는 (모든 것이 파일이기 때문에) 아직도 존재합니다.GNU/Linux는 이전 세대의 교훈을 다시 한 번 잊고 있습니다.그리고 그들과 함께 오는 힘을 잃었습니다.

따라서 프로세스가 내보내는 실제 데이터가 존재하는 가상 터미널 프로그램의 버퍼에 저장되게 됩니다.표준 Linux 가상 터미널 콘솔 또는 xterm, Konsole, GNOME 터미널과 같은 X 프로그램입니다.그런 다음 그래픽 API를 통해 렌더링합니다.

즉, 그 내용을 알고 싶다면, 그 프로그램들에게 물어봐야 합니다!

정답

이 표준 인터페이스는 ANSI 터미널 명령어입니다.(텍스트를 컬러풀하게 하거나 커서를 움직이거나 마우스 포인터의 위치를 찾거나 최신 단말기에서 픽셀을 그릴 수 있습니다.
안타깝게도 버퍼 접근을 지원하는 단말기는 없습니다.
게다가, 각 유저가 다른 인터페이스를 가지는 것도 곤란합니다.

다행히 버퍼 접근을 지원하는 자체 중간 레이어 가상 단말기를 삽입할 수 있습니다.
SSH를 통해 접속할 경우 세션 도중 연결이 끊길 수 있는 경우뿐만 아니라 로그인 셸로 사용하는 것이 좋습니다.또한 세션을 다른 곳으로 이동하려는 경우(예: X를 재시작하는 경우)

실제로 하는 방법, 실제로 하는 방법

?screen"에 기록할 수 . 그러면 전체 세션을 "파일"에 기록할 수 있습니다.Unix unix unix unix unix unix unix unix unix unix unix unix unix unix unix unix unix 。명명된 파이프를 사용할 수 있습니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

바깥부분

'가 '외부'의.bashrc하다

    if shopt -q login_shell && [[ $- == *i* ]]; then # Login + interactive?
      export ANS_FIFO=/tmp/$$.history ## $$ = current shell PID.
      mkfifo -m 600 $ANS_FIFO
      screen -OU -L -Logfile $ANS_FIFO # With optimal mode + UTF-8
      rm $ANS_FIFO # Clean up
    fi
내부 부품

이제 '.$ANS_FIFO$ANS 실행 후 .$ANS다음과 같이 합니다.

    export PROMPT_COMMAND+='[[ -v ANS_FIFO ]] && export ANS="$(< $ANS_FIFO)"'

서 ""가 "bash"인지 합니다.$ANS_FIFO설정되고 .$ANS '아예'라고 .bashrc

이것은 기술적으로 유효하며, 테스트(탈옥 시퀀스 및 UTF-8 포함)를 실시했습니다만,

작업 내용:

문제:이론적으로는 이것이 동작하지만 실제로는 이 빠르게 행업합니다.이는 명명된 파이프가 버퍼가 아니라 동기식으로 취급되기 때문입니다(Linux에서는 버퍼가 존재하며 프로그래밍 방식으로 크기를 변경할 수도 있습니다).$ANS_FIFO있으면 screen(아마도 텍스트의 한 줄)이 돌아올 때까지 쓰는 것.

  • , 패턴을 받을 해, 「」( 「 서버」)를 설정하는이 생각할 수 있습니다.$ANS 럼과 .$ANS후 , 전에 는 "Dell"이 "Dell"을 의미함을 합니다.$ANS항상 어떤 것으로만 설정된다.screen마지막 프롬프트 이후 기록되었으며, 읽어도 잠기지 않습니다.
  • 훨씬 낫지만 어려운 또 다른 해결책은 단말기에 직접 인터페이스를 추가하는 것입니다.으로 셸의 합니다.$ANS년 동안 처럼요.마치 전자계산기가 수십 년 동안 해왔던 것처럼요.

아쉽게도 반나절 동안 앉아있었기 때문에 지금 다른 일을 하러 가야 합니다.만약 누군가가 저보다 먼저 이것을 실행할 의향이 있다면, 제 답변을 자유롭게 수정해 주세요.할 수 없는 경우는, 자신의 답변을 추가합니다.다음에 필요할 때 내가 직접 할 수도 있고 안 할 수도 있어.:)

-exec을 사용하여 명령 출력에 대해 명령을 실행할 수 있습니다..find음음음음:

find . -name anything.out -exec rm {} \;

여기서 말하는 것은 -> 현재 폴더에서 anything.out이라는 파일을 찾습니다.파일이 발견되면 삭제합니다.찾을 수 없는 경우 -exec 이후의 나머지 부분은 건너뜁니다.

언급URL : https://stackoverflow.com/questions/24283097/reusing-output-from-last-command-in-bash

반응형