Incluir comando no arquivo de saída?

17

Desculpe pelo título confuso!

Suponha que eu corra

apt-cache depends kde-window-manager > ~/Desktop/kwin-depends

Vou pegar um arquivo chamado "kwin-depende" na minha pasta da área de trabalho.

Existe algum truque para incluir o comando que eu emiti como parte do arquivo, de preferência no início do arquivo?

Portanto, pelo menos em 14.04 LTS, as primeiras linhas seriam assim:

apt-cache depends kde-window-manager > ~/Desktop/kwin-depends

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>

Em vez de apenas assim:

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
Justiça para Monica
fonte
3
Como agora existem muitas outras soluções flexíveis e boas, considere inaceitar a resposta que sugere escrever manualmente o comando no arquivo digitando-o duas vezes e aceitar uma das soluções versáteis.
Byte Commander

Respostas:

18

Eu usaria apenas uma função simples. Adicione isso ao seu ~/.bashrcarquivo:

function runcom(){
    echo "$@"
    ## Run the command
    $@
}

Agora, sempre que quiser executar um comando e imprimi-lo, você pode:

runcom apt-cache depends kde-window-manager > out

O acima produz este arquivo:

$ cat out
apt-cache depends kde-window-manager
kde-window-manager
  Depends: perl
  Depends: kde-runtime
  Depends: kde-style-oxygen
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
    libegl1-mesa
  Depends: libgcc1
 |Depends: libgl1-mesa-glx
  Depends: <libgl1>
    libgl1-mesa-swx11
    libgl1-mesa-glx
 |Depends: libgles2-mesa
  Depends: <libgles2>
    libgles2-mesa
  Depends: libice6
  Depends: libkactivities6
  Depends: libkcmutils4
  Depends: libkdeclarative5
  Depends: libkdecorations4abi2
  Depends: libkdecore5
  Depends: libkdeui5
  Depends: libkio5
  Depends: libknewstuff3-4
  Depends: libkwineffects1abi5
  Depends: libkwinglesutils1
  Depends: libkwinglutils1abi2
  Depends: libkworkspace4abi2
  Depends: libplasma3
  Depends: libqt4-dbus
  Depends: libqt4-declarative
  Depends: libqt4-script
  Depends: libqtcore4
  Depends: libqtgui4
  Depends: libsm6
  Depends: libstdc++6
  Depends: libwayland-client0
 |Depends: libwayland-egl1-mesa
  Depends: <libwayland-egl1>
    libwayland-egl1-mesa
  Depends: libx11-6
  Depends: libx11-xcb1
  Depends: libxcb-composite0
  Depends: libxcb-damage0
  Depends: libxcb-image0
  Depends: libxcb-keysyms1
  Depends: libxcb-randr0
  Depends: libxcb-render0
  Depends: libxcb-shape0
  Depends: libxcb-shm0
  Depends: libxcb-sync1
  Depends: libxcb-xfixes0
  Depends: libxcb-xtest0
  Depends: libxcb1
  Depends: libxcursor1
  Depends: libxext6
  Depends: libxrandr2
  Depends: libxxf86vm1
  Breaks: kde-style-bespin
  Breaks: kde-style-bespin:i386
  Breaks: <kde-style-skulpture>
  Breaks: <kde-style-skulpture:i386>
  Breaks: kde-workspace-data
  Breaks: <kde-workspace-data:i386>
  Breaks: kdeartwork-theme-window
  Breaks: kdeartwork-theme-window:i386
  Breaks: <kdebase-workspace-data>
  Breaks: <kdebase-workspace-data:i386>
  Breaks: kwin-style-crystal
  Breaks: kwin-style-crystal:i386
  Breaks: kwin-style-dekorator
  Breaks: kwin-style-dekorator:i386
  Breaks: kwin-style-qtcurve
  Breaks: kwin-style-qtcurve:i386
  Replaces: kde-workspace-data
  Replaces: <kde-workspace-data:i386>
  Replaces: <kdebase-workspace-data>
  Replaces: <kdebase-workspace-data:i386>
  Conflicts: kde-window-manager:i386
Terdon
fonte
Não pretendo mover as traves aqui, mas existe uma maneira de fazer com que seu código aceite aliases também? Por exemplo, se eu aliasar apt-cache dependspara acd, recebo "Nenhum comando 'acd' encontrado, você quis dizer: ..." quando eu executo runcom acd leafpad > out.
Justice for Monica
Os aliases do @DKBose são definidos no arquivo .bashrc, não no shell, e as funções chamam apenas os arquivos binários localizados na variável $ PATH. Mas você pode fazer um truque simples. Por exemplo, lsé um alias ls --color=auto' na realidade. O que você poderia fazer (contanto que não há aspas simples ou duplas em seu nome alternativo), é a seguinte: $ terdonsFunction $(alias ls | awk -F '=' '{$1="";print}'| tr "'" " ") .
Sergiy Kolodyazhnyy
OU transforme seu comando em uma variável. Como eu mostrei na minha resposta antes. MYCOMMAND="apt-cache depends"; terdonsFunction $MYCOMMAND leafpad > out.txt
Sergiy Kolodyazhnyy
@Serg, consulte a resposta de GARCIN David: askubuntu.com/a/688936/248158
Justice for Monica
Essa é a resposta "óbvia" e funciona muito bem, a menos que algum dos argumentos envolva código que execute e tenha efeitos colaterais que possam se acumular. Este é um caso extremo, portanto não ocorreria com muita frequência.
Joe
11

Você pode fazer:

tee file.txt <<<'apt-cache depends kde-window-manager' | bash >>file.txt

A mesma coisa usando em echovez de Here strings ( <<<):

echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt
  • tee irá gravar em STDOUT e também no arquivo file.txt

  • O STDOUT de teeie apt-cache depends kde-window-managerserá alimentado bashpara executar o comando e anexar o STDOUT a file.txt.

Exemplo:

$ echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt

$ cat file.txt 
apt-cache depends kde-window-manager
kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
heemail
fonte
1
Ótima resposta! Simples e direto ao ponto! Eu estava tentando um, teemas o meu continuava falhando. Bom trabalho! +1
Terrance
@Seth Eu também pensei sobre o jogo com os descritores de arquivos, mas teeparece puro :)
heemayl
11

O mais minimalista - as abordagens 4 e 3, ambas poderiam ser convertidas em função; # 2 meu favorito - awk. # 1 usa scriptcomando - ferramenta muito versátil, útil para gravar linha de comando em geral; aplicável em qualquer lugar, para o que você quiser gravar.

Abordagem 1: Existe um /usr/bin/scriptcomando (que vem com o ubuntu por padrão) para registrar a saída da linha de comando, que captura tudo, junto com o prompt e o comando. Para salvar apenas um comando e sua saída em um arquivo específico, use o -csinalizador e especifique o arquivo de saída. Exemplo

xieerqi:$ script -c 'apt-cache depends gnome-terminal' outputFile.txt
Script started, file is outputFile.txt
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
     (extra output omitted)
Script done, file is outputFile.txt

xieerqi:$ cat outputFile.txt                                              
Script started on 20151022 星期四 085846
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  (extra output omitted)

Script done on 20151022 星期四 085846

Abordagem 2: hakery awk

O Awk possui uma system()função que permite executar comandos shell a partir de awkscript ou comando . A saída será exibida na tela, comando primeiro, saída seguinte. Para redirecionar o que você vê para um arquivo, use o >operador.

Isso pode ser feito de duas maneiras - peça ao usuário para inserir itens do stdin ou como argumento da linha de comando. O primeiro é mais fácil de alcançar, portanto, publicando isso.

(1) awk 'BEGIN{ print "Enter command to run: "; getline com < "/dev/stdin"; system(com) }'

 awk 'BEGIN{ print "Enter command to run: "; getline com < "/dev/stdin"; system(com) }'
Enter command to run: 
apt-cache depends gnome-terminal
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
  Depends: libglib2.0-0 
  (extra output omitted)

(2) versão da linha de comando args; não incluindo a saída para evitar que a resposta seja longa demais. Novamente, acrescente >para redirecionar para o arquivo

awk 'BEGIN{for (i=1; i<= ARGC; i++) myString = myString"  "ARGV[i]; print myString; system(myString)  }' apt-cache depends gnome-terminal

Abordagem # 3: peça ao bash para fazer o trabalho por você

xieerqi@eagle:~$ bash -c ' MYCOMMAND="apt-cache depends gnome-terminal"; echo $MYCOMMAND ; $MYCOMMAND    '
apt-cache depends gnome-terminal
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
  Depends: libglib2.0-0

Redirecionar para arquivo com o >operador:

bash -c ' MYCOMMAND="apt-cache depends gnome-terminal"; echo $MYCOMMAND ; $MYCOMMAND ' > output.txt

Abordagem # 4: (meu segundo favorito)

Inspirado na publicação de ByteCommander; podemos usar reade depois executar os comandos necessários no subshell

read command && (printf "COMMAND: %s" "$command";printf "\n+++++++\n"; sh -c "$command")

Exemplo de execução:

xieerqi:$ read command && (printf "COMMAND READ: %s" "$command";printf "\n+++++++\nOUTPUT\n"; sh -c "$command")                                       
printf "This was a triumph; I'm making a note here - huge success"
COMMAND READ: printf "This was a triumph; I'm making a note here - huge success"
+++++++
OUTPUT
This was a triumph; I'm making a note here - huge success

Abordagem # 5:

Use echoou here string(aka <<< "string") para fornecer argumentos para sh -catravésxargs

xieerqi:$ echo "apt-cache policy gnome-terminal" | xargs -I {} bash -c 'echo {}; {}'                                                            
apt-cache policy gnome-terminal
gnome-terminal:
  Installed: 3.6.2-0ubuntu1
  Candidate: 3.6.2-0ubuntu1
  Version table:
 *** 3.6.2-0ubuntu1 0
        500 http://us.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

E se você quiser, você pode usar esse mesmo truque com um alias:

xieerqi:$ printAndRun <<< "apt-cache policy gnome-terminal"                                                                                     
apt-cache policy gnome-terminal
gnome-terminal:
  Installed: 3.6.2-0ubuntu1
  Candidate: 3.6.2-0ubuntu1
  Version table:
 *** 3.6.2-0ubuntu1 0
        500 http://us.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

xieerqi:$ type printAndRun
printAndRun is an alias for 'xargs -I {} bash -c "echo {}; {}"'
Sergiy Kolodyazhnyy
fonte
Bom, mas não inclui o comando da mesma forma que o código da Arronical.
Justice for Monica
@DKBose adicionarei outra abordagem que incluirá o comando. Cinco minutos
Sergiy Kolodyazhnyy 22/10/2015
@DKBose, como está minha abordagem nº 2?
Sergiy Kolodyazhnyy 22/10/2015
Isso é inteligente, awkrealmente é um amiguinho muito configurável, não é! O script `parece útil para alguns outros usos também.
Arronical
1
Essa é a melhor resposta, pois o uso de script evita efeitos colaterais de argumentos que podem executar código quando exibido com eco, etc. - tornando a segunda execução pretendida possivelmente fornecendo resultados diferentes do que se o comando fosse executado separadamente.
Joe
6
  1. Começar script -q outputfile
  2. Execute seu comando
  3. Pressione Ctrl-D
  4. Abra o arquivo outputfile

Exemplo

Começar script

[aboettger:~/tmp] % script -q ~/Desktop/kwin-depends

Inicie seu comando

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
[aboettger:~/tmp] % 

Pressione Ctrl-D

Script done, file is /home/aboettger/Desktop/kwin-depends

Mostre seu comando e saída

[aboettger:~/tmp] % cat ~/Desktop/kwin-depends

e você verá algo assim

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
AB
fonte
5

Se você deseja expansão de alias (somente bash), pode fazê-lo desta maneira:

function runcmd
{
    local check_cmd=${BASH_ALIASES[$1]}

    if [ -z "$check_cmd" ]; then
        check_cmd=$1
    fi

    shift #skip 1st arg

    echo "$check_cmd $@"
    $check_cmd $@
}

Agora você pode executar

runcmd acd leafpad > out
GARCIN David
fonte
4

Pode haver uma maneira mais fácil, mas você pode fazê-lo por um script:

#!/bin/sh
echo $1
apt-cache depends $1

Crie um arquivo scriptcom este conteúdo na sua pasta Home e conceda permissão de execução

chmod +x script

Execute da seguinte maneira:

./script kde-window-manager > ~/Desktop/kwin-depends
Pilot6
fonte
Essa abordagem tem a vantagem de facilitar a repetição dessa linha de comando posteriormente, se você quiser! Você também pode gravar o redirecionamento no script, para que script.shsempre crie um arquivo chamado script.logcom sua saída.
Gaurav
4

Solução extremamente simples usando uma função Bash de uma linha

Preparação:

Essa abordagem usa uma função personalizada do bash para fornecer a funcionalidade desejada. Você o define executando a seguinte linha na sua sessão do terminal. observe que você pode escolher qualquer nome válido de variável bash em vez de runandlog:

runandlog () ( IFS=' '; printf "[%s] $ %s\n%s\n" "$USER" "${*:2}" "$("${@:2}")" | tee -a "$1" | tail -n +2; )

No entanto, isso persiste apenas para a sessão atual do Bash, ou seja, depois de fechar a janela do terminal, a função desaparece.
Se você tentou e gostou, pode disponibilizá-lo sempre editando seu ~/.bashrcarquivo e anexando esta linha ao final.

Como usar:

Depois de definir a função, você pode usá-la para executar comandos enquanto registra o próprio comando e sua saída em um arquivo. Você pode até adicionar mais informações, como o usuário que a executou, que eu já incluí na função, ou a hora exata em que ela foi executada. Solicitações de recursos nos comentários são bem-vindas! :)

A sintaxe é simples:

runandlog LOGFILENAME YOUR-COMMAND-WITH-ARGUMENTS

Exemplo:

Um exemplo de sessão como usuário bytecommander, operando a partir do diretório inicial, pode ser assim:

bytecommander: ~ $  runandlog mylogfile fortune
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos

O que resultará em um novo arquivo mylogfile (se já existir, a função anexará a saída a ele!) No diretório atual com o conteúdo:

[bytecommander] $ fortune 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos
Byte Commander
fonte
3

Um truque bastante inábil, mas funcional, seria:

(echo "apt-cache depends kde-window-manager" && apt-cache depends kde-window-manager) > ~/Desktop/kwin-depends

Feio, mas funciona!

Arronical
fonte
Estou aceitando esta resposta porque a solução é mais amplamente aplicável.
Justice for Monica
@DKBose Você precisará digitar o módulo duas vezes. Mas a solução com um script é realmente universal.
Pilot6
Sinto muito por não aceitar esta resposta, mesmo que ela faça o que pedi. Espero que você não se importe!
Justice for Monica
2
Não é um problema @DKBose, eu sabia que era uma solução bastante deselegante ao enviar a resposta e aprendi algumas coisas boas das respostas alternativas postadas.
Arronical 26/10
2

Você pode simplesmente passar o comando para uma função que imprime o comando primeiro e a saída do comando posteriormente (os redirecionamentos são mantidos fora do comando impresso intencionalmente, você pode facilmente mudar isso removendo as aspas do comando e imprimindo e executando em $@vez disso de $1na função):

function myfunction() {
    printf "%s\n\n" "$1"
    $1
}
$ myfunction "printf \"bar\n\"" > foo
$ cat foo
printf "bar\n"

bar

Para adicionar o comando posteriormente, você pode executar este comando, que irá inserir o último comando executado na parte superior de um arquivo:

<<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
  • <<<"[...]": aqui string; [...]é redirecionado para cat's stdin;
  • $(<foo): substituição de comando; é substituído pelo conteúdo de "foo";
  • cat [...] - >foo: Concatena stdinpara [...]e saídas para "foo";
  • <([...]): substituição de processo: é substituído por um descritor de arquivo contendo a saída de [...];
  • history 2 | sed -n '1s/ [0-9][0-9]* \(.*\)/\1\n/p': gera os dois últimos comandos, remove dois espaços seguidos por um ou mais dígitos seguidos por dois espaços da primeira linha e os imprime;
$ printf "bar\n" >foo
$ <<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
$ cat foo
printf "bar" >foo

bar
kos
fonte
Por que você está apenas imprimindo $1? E não há necessidade eval.
Ter23
@terdon Bem, a idéia era manter os redirecionamentos fora do comando impresso, pois achei que isso poderia parecer melhor no caso do OP. No entanto, se eu mudar agora, seria idêntico à sua resposta. No entanto, sim, evalnão é necessário, não sei por que o adicionei antes. Obrigado.
kos