Como reutilizo a última saída da linha de comando?

43

Gostaria de saber como reutilizar a última saída do console, ou seja:

pv-3:method Xavier$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/Library/Python/2.6/site-packages
pv-3:method Xavier$ cd **LASTOUTPUT**
methodofaction
fonte
7
Você não pode; há alguma explicação de fundo aqui . Sua melhor aposta é executar o comando novamente, como visto nas duas respostas postadas até agora.
Gilles 'SO- stop being evil'
Você não pode capturar a saída enviada diretamente para um dispositivo como /dev/tty, mas deve ser possível capturar qualquer coisa enviada para stdoutou stderrque possa ser adequada.
22411 Mikel
@ Gilles - a menos que você use a resposta de @ mattdm, é claro!
11111 simon
@ Gilles: mas pode haver um shell criado por alguém que capture (e repasse) as saídas dos comandos e disponibilize as saídas capturadas para que o usuário se refira a partir de outros comandos. Talvez, existem ainda algumas conchas existentes, não tão populares que permitem isso com mais ou menos complicações ...
IMZ - Ivan Zakharyaschev
1
possível duplicação de Usando texto dos comandos anteriores 'output
Gilles' SO- stop be evil '

Respostas:

39

Supondo que o bash:

% python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.7/site-packages
% cd $(!!)
cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
% pwd
/usr/lib/python2.7/site-packages
jsbillings
fonte
1
Obrigado! Não é fácil digitar, mas é melhor do que o mouse.
methodofaction
2
Você também pode usar backticks (que não consigo descobrir como tornar essa interface não wikify) em vez de $ (), mas eu achei desconfortável que eu batesse em backtick-shift-1-shift-1-backtick , e estou tentando adquirir o hábito de usar $ () quando possível, por uma questão de legibilidade.
jsbillings
@jsbillings veja minha resposta abaixo. Digitei \ `para exibir` na resposta. E para exibir '\', como de costume, digite '\\'.
yasouser 11/03/11
3
+1 Fiquei me perguntando como aninhar `backtick-commands`! cd $(dirname $(which python))aqui vou eu!
Ed Brannin
21
Apenas uma observação, lembre-se de que isso está executando novamente o comando. Se o seu comando tiver efeitos colaterais, isso pode não funcionar para você.
Rich Homolka
13

Ainda não mencionado, use uma variável:

dir=$( python -c ... )
cd "$dir"
Glenn Jackman
fonte
3
Exatamente. Por ser uma casca, as pessoas geralmente esquecem os recursos de idioma que o Bash fornece, como loops e atribuição.
Evan
pode apenas dizercd $dir
temporary_user_name
3
@Aerovistae, as aspas são necessárias se você não sabe onde o valor vem de:
Glenn Jackman
@glenn, (eu sei que isso poderia ser outra pergunta, mas se a resposta for curta :) você poderia explicar mais / fornecer um exemplo em que o não uso de aspas poderia quebrar as coisas?
Alexey
2
A explicação canônica é unix.stackexchange.com/questions/171346/…
glenn jackman
8

Todas as outras soluções envolvem a modificação do fluxo de trabalho ou a execução do comando duas vezes, o que pode não ser adequado se levar muito tempo para ser executado ou não for repetível (por exemplo, exclui um arquivo - a execução do arquivo resultaria em um resultado diferente).

Então, aqui está uma ideia mais complicada, se você precisar:

.bashrc

exec > >(tee -a ~/$$.out)

PROMPT_COMMAND='LASTLINE=$(tail -n 1 ~/$$.out)'

trap 'rm ~/$$.out' EXIT

prompt do bash

$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.6/dist-packages
$ cd $LASTLINE
$ pwd
/usr/lib/python2.6/dist-packages

Isso tem alguns problemas, então serve apenas como ponto de partida. Por exemplo, o arquivo de saída ( ~/<pid>.out) pode crescer muito e encher seu disco. Além disso, todo o seu shell pode parar de funcionar se teemorrer.

Ele poderia ser modificado para capturar apenas a saída do comando anterior usando preexece precmdhooks no zsh, ou uma emulação deles no bash, mas isso é mais complicado de descrever aqui.

Mikel
fonte
6
A ideia básica é boa, mas a implementação não é. A saída padrão na sessão do shell não é um terminal, mas um canal, o que fará com que alguns programas se comportem de maneira diferente. Não haverá sincronização entre as gravações no stdout e as gravações no stderr ou diretamente no tty, portanto, por exemplo, você poderá ver a saída do comando exibida após o próximo prompt. Você também não está protegido teecontra sinais (tente pressionar Ctrl+Ce executar mais alguns comandos). Use o scriptutilitário que não possui nenhum desses problemas.
Gilles 'SO- stop being evil'
Bom saber! Ainda estou trabalhando no básico da minha linha de comando, então isso é possivelmente um exagero para mim, além de querer poder usá-lo em qualquer computador, mas lembrarei se algum dia atingir um bom nível.
methodofaction
8

Um rascunho de trabalho para um shell tradicional:

ttyid=$(readlink /proc/$$/fd/1)
\___/   \______/ \___/ |  |  |
  |         |      |   |  |  \- 0: stdin 
  |         |      |   |  |     1: stdout <- our interest
  |         |      |   |  |     2: stderr
  |         |      |   |  \- fd is, maybe, filedescriptor
  |         |      |   |
  |         |      |   \- $$ is the PID of the current process (shell,
  |         |      |      in our case)
  |         |      |
  |         |      \- you know, much runtime stuff is here
  |         |
  |         \- readlink extracts the symbolic link of /proc/$$/fd/1
  |            lrwx------ 1 stefan stefan 64 2011-03-18 09:11
  |            /proc/22159/fd/1 -> /dev/pts/4
  |
  \- /dev/tty3 for real shell, /dev/pts/3 for xterm

Agora podemos colocar a tela em um arquivo. Precisa de sudo.

id=${ttyid//\/dev\/tty}
sudo cat /dev/vcs$id > screen.dump

A propósito screendump: o programa chamado não funciona mais para mim. Talvez apenas para kernels antigos. / dev / pts / N também não funcionou para mim. Talvez você precise de algum MKDEV opcional em / dev - lembro-me sombriamente de alguns /dev/cuaN, mas posso estar errado.

Gostaríamos de canalizar a saída em vez de usar screen.dump. Mas de alguma forma isso não funciona - às vezes aguarda ENTER.

A captura não é um arquivo de texto normal com alimentações de linha, mas com - por exemplo - caracteres de 80 x 50 em uma sequência.

Para escolher as duas últimas linhas, uma para a saída do comando e uma para a linha de prompt, eu a reverto, pego 160 caracteres, reverto novamente e escolha 80.

rev vcs4.dat | sed 's/\(.\{160\}\).*/\1/g' | rev | sed 's/\(.\{80\}\).*/\1/g'

Caso você já tenha se perguntado, por que existe um revprograma?

Crítica:

  • Os primeiros comandos são inseridos, movendo a linha ahed. Bem - apenas um exercício numérico para escolher a terceira linha final ou algo assim. Eu trabalhei principalmente em uma janela diferente.
  • Nem todo mundo tem uma tela de 80x50. Bem, sim, nós sabemos. Existem $ COLUMNS e $ ROWS para seu prazer.
  • A saída não está sempre na parte inferior. Uma concha fresca e jovem pode estar nas fileiras superiores. Bem - simples assim: avalie qual shell está sendo executado. Qual prompt é usado. Faça alguma detecção imediata e encontre a última linha com um prompt de shell. A linha anterior (ou 2. anterior) deve conter o diretório

O primeiro diagrama é feito com o explica.py

Usuário desconhecido
fonte
1, me obrigou a fazer #alias tee2tty='tee $(readlink /proc/$$/fd/1)'
Tobias Kienzler 18/03/11
7

Tente o seguinte:

$ cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
$ pwd
/Library/Python/2.6/site-packages
bahamat
fonte
6

Então, aqui está uma resposta:

Se você estiver executando no X, selecione a saída que deseja com o mouse para copiá-la e clique com o botão do meio para colá-la.

Se você estiver executando em um console de texto, poderá fazer uma coisa semelhante com o gpm .

mattdm
fonte
1
+1 - boa resposta! você pode conseguir a mesma coisa, mesmo se não estiver executando o X, usando a tela GNU ( gnu.org/software/screen ).
quer
1
Parecia tão óbvio que eu hesitava em dizer isso. Mas todo mundo está tão ocupado sendo esperto. :)
mattdm
é a única resposta aqui que permite que o OP reutilize a última linha - tudo o mais implica executar o comando novamente, o que pode estar em qualquer lugar entre absolutamente irrelevante e catastrófico :) Mas o OP disse reutilizar .
21711
@ Simon: Na verdade, minha resposta não. Nem Glenn's.
Mikel
@ Mikel: Verdade, mas eles exigem que você faça algo com antecedência ou corretamente da primeira vez.
mattdm
1

(Infelizmente, não é uma resposta funcional, mas ainda algo curioso. Alguém interessado pode tentar concluir a implementação do recurso que vou falar sobre isso.)

No eshellEmacs, eles queriam ter esse recurso, mas ele não foi implementado de maneira completa (o que é refletido na documentação ).

Por exemplo:

~ $ pwd
~
~ $ /bin/echo $$
~
~ $ /bin/pwd
/home/imz
~ $ /bin/echo $$

~ $ 

Veja bem, apenas a saída dos componentes internos pode ser capturada na $$variável.

Mas bem, alguma programação elisp (cf. eshell-mark-outputimplementação em "esh-mode.el"), e você pode implementar uma função que "marque" a última saída e a retorne como resultado da função; para que você possa usar essa função em um comando eshell que você está solicitando - as funções elisp podem ser usadas em comandos eshell com a sintaxe elisp usual, ou seja, entre parênteses, assim:

~ $ /bin/echo (buffer-name)
*eshell*
~ $ /bin/echo (car '(a b c))
a
~ $ 
imz - Ivan Zakharyaschev
fonte
0

Se você perceber que deseja reutilizar a saída antes de clicar Enter, você pode salvá-la em uma variável: adicione tmp=$(no início da linha e )no final. (Isso remove qualquer linha em branco no final da saída do comando e, de fato, remove qualquer nova linha final; isso raramente importa.)

tmp=$(python -c )
echo "$tmp"
cd "$tmp"

Se seu shell for ksh ou zsh, aqui está uma função útil que você pode usar para tornar isso mais automático. (Isso não ajuda no bash porque requer que o último comando em um pipeline seja executado no shell pai, o que é apenas o caso no ksh (não no pdksh) e no zsh.)

keep () {
  local line IFS=$'\n'
  kept=
  while read -r line; do
    printf '%s\n' "$line"
    kept=$kept$line$IFS
  done
}
alias keep=k

Use desta maneira:

python -c  |k
cd $kept
Gilles 'SO- parar de ser mau'
fonte
0
cd $(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" | tee $(readlink /proc/$$/fd/1))

(baseado na resposta do 4485 )

Isso é muita digitação, então crie um alias:

alias tee2tty='tee $(readlink /proc/$$/fd/1)'

Em seguida, basta ligar cd $(python -c ... | tee2tty)

É claro que isso exige que você já saiba o que deseja fazer com a saída, mas tem a vantagem de chamar o comando apenas uma vez.

Tobias Kienzler
fonte
0
$ cd \`python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"\`

fará o truque.

Leia aqui para mais detalhes: Substituição de comando .

yasouser
fonte
1
arumug: bahamat já postou quase a mesma resposta . Sua versão com backticks nem sempre funcionará se já houver backticks no comando.
Gilles 'SO- stop be evil'
0

Existe uma solução melhor:

Basta imprimir !!após o comando executado e você obterá resultados repetidos.

Por exemplo

insira a descrição da imagem aqui

Original:

https://askubuntu.com/questions/324423/how-to-access-the-last-return-value-in-bash

Tebe
fonte
!!não repete o resultado do último comando, ele executa novamente o último comando. Se jot -r 1 0 1000retornar um único número aleatório entre 0 e 1000, depois de executar o comando uma vez e obter 539, a execução !!provavelmente fornecerá outro número. !!também pode ser indesejável se o comando anterior levar um tempo significativo para ser executado ou repetir uma operação que não deve ser repetida (como alterar um arquivo).
Caleb
1
boa pegada. Embora exista uma maneira mais fácil de provar que estou errado: eco $ RANDOM; !!
Tebe
Doce - não sabia disso! Obrigado.
Caleb