bash ecoa a linha de comando executada na própria linha de comando (não em um script)

2

Para fins de documentação, quero redirecionar para o arquivo stdout e stderr de um comando que eu executo. Por exemplo, eu iria correr (meu comando é menos trivial do que o alias ll , mas provavelmente não importa):

$ ll > out-err.dat 2>&1
$ cat out-err.dat
drwxr-xr-x 39 us00001 us00001    4096 jul 31 14:57 ./
drwxr-xr-x  3 root    root       4096 feb  2 06:06 ../
-rw-------  1 us00001 us00001   62226 jul 31 11:56 .bash_history
...

Também para fins de documentação, quero armazenar no mesmo arquivo de saída a linha de comando que usei. O comportamento pretendido e a saída é

$ [NEW COMMAND LINE]?
$ cat out-err.dat
[NEW COMMAND LINE]   <- This first line would contain the command line used
drwxr-xr-x 39 us00001 us00001    4096 jul 31 14:57 ./
drwxr-xr-x  3 root    root       4096 feb  2 06:06 ../
-rw-------  1 us00001 us00001   62226 jul 31 11:56 .bash_history
...

Como isso pode ser feito? Eu sei que eu poderia escrever um script bash e executá-lo, então o comando permaneceria documentado separadamente. Eu poderia escrever mais um script para ecoar a linha de comando para arquivo e, em seguida, executá-lo com o redirecionamento para o mesmo arquivo. Estou procurando uma solução possível sem script.

EDITAR : Feedback sobre uma boa resposta. Isso não se encaixaria como um comentário.
Eu testei com o comando echo_command ll echo_command.sh ../dir > out-err.dat 2>&1 .
O script echo_command.sh , que eu source , contém as definições das funções. % ../dir é um diretório inexistente, para forçar alguma saída para stderr .

Método 1 : Funciona bem, exceto por dois problemas:

  • Não entende aliases ( ll neste caso; ao substituir com ls funcionou).

  • Não grava a parte de redirecionamento.

Método 2 : Não funciona tão bem assim. Agora, a parte de redirecionamento também é impressa, mas a linha de comando é impressa na tela, em vez de redirecionada para o arquivo.

EDITAR : Feedback sobre um comentário postado, sobre um utilitário script . É bastante versátil, ainda mais com scriptreplay .
script pode ser chamado sozinho, o que produz um shell interativo (ele não manteria o histórico recente do shell pai)
Também pode ser chamado como script -c <command> <logfile> . Esta última forma corresponde ao objetivo do OP, mas não armazena o próprio comando no arquivo de log. Produz (pelo menos em casos de base) a mesma saída que <command> > <logfile> 2>&1 .
Então parece que isso não é útil aqui.

    
por sancho.s 31.07.2018 / 23:10

2 respostas

2

Você poderia usar uma função como esta:

echo_command() { printf '%s\n' "${*}"; "${@}"; }

Exemplo:

$ echo_command echo foo bar baz
echo foo bar baz
foo bar baz
$ echo_command uname
uname
Linux

Como Tim Kennedy disse, há também um comando script muito útil:

$ script session.log
Script started, file is session.log
$ echo foo
foo
$ echo bar
bar
$ echo baz
baz
$ exit
exit
Script done, file is session.log
$ cat session.log
Script started on 2018-07-31 16:30:31-0500
$ echo foo
foo
$ echo bar
bar
$ echo baz
baz
$ exit
exit

Script done on 2018-07-31 16:30:43-0500

Atualizar

Se você também precisar registrar os redirecionamentos e basicamente todas as sintaxes do shell (note que adicionei uma pequena mensagem Command line: para identificar facilmente o comando sendo executado):

echo_command() {
  local arg
  for arg; do
    printf 'Command line: %s\n' "${arg}"
    eval "${arg}"
  done
}

Lembre-se de que você deve tomar muito cuidado com as citações, pois eval é usado:

$ echo_command 'echo foo > "file 2"; cat "file 2"'
Command line: echo foo > "file 2"; cat "file 2"
foo

Ele também aceita vários comandos de uma só vez, em vez de apenas um:

$ echo_command 'echo foo' 'echo bar' 'echo baz'
Command line: echo foo
foo
Command line: echo bar
bar
Command line: echo baz
baz
    
por 31.07.2018 / 23:23
1

Você pode usar o mecanismo xtrace no qual o shell imprime os comandos que está sendo executado para stdout:

(set -x; ls -l) > out-err.dat 2>&1

Altere $PS4 de seu padrão de "+ " (na maioria dos shells) para qualquer outra coisa, se você não gostar (torne-o vazio se você não quiser um prefixo).

Como uma função:

log_into() ( # args: output-file command args
   exec > "$1" 2>&1
   shift
   PS4='Running: '
   set -o xtrace
   "$@"
)

log_into out-err.dat ls -l
    
por 03.08.2018 / 10:23