bash echoコマンドラインはコマンドライン自体で実行されます(スクリプトではありません)。

bash echoコマンドラインはコマンドライン自体で実行されます(スクリプトではありません)。

これは、文書化目的で実行するコマンドからstdoutファイルとstderrファイルにリダイレクトすることを意味します。たとえば、次のコマンドを実行します(私のコマンドはエイリアスよりも簡単ではありませllんが、おそらく重要ではありません)。

$ 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
...

また、文書化の目的で同じ出力ファイルに使用するコマンドラインを保存したいと思います。予想される動作と出力は次のとおりです。

$ [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
...

これはどのように達成できますか? 私はbashスクリプトを作成して実行して、コマンドを別々に記録できることを知っています。コマンドラインをファイルに反映し、同じファイルにリダイレクトして実行するスクリプトをさらに作成することもできます。可能なスクリプトレスソリューションを探しています。


編集する:良い答えをフィードバックしてください。これはコメントとして適切ではありません。
命令でテストしてみましたecho_command ll echo_command.sh ../dir > out-err.dat 2>&1。私の
スクリプトには関数定義が含まれています。存在しないディレクトリなので、一部の出力が 。echo_command.shsource
../dirstderr

方法1:2つの問題を除いて、それは素晴らしい動作します。

  • エイリアスがわかりません(llこの場合は交換がls機能します)。

  • リダイレクト部分は記録しません。

方法2:効果はあまり良くありません。リダイレクトされた部分も印刷されますが、コマンドラインはファイルにリダイレクトされるのではなく画面に印刷されます。


編集する:ユーティリティについて公開されたコメントに対するフィードバックscript。非常に汎用性があり、インタラクティブシェルを作成します scriptreplay。またはで呼び出すことができます。最後の形式はOPの目標に対応しますが、コマンド自体は次のようになります。ログファイルに保存されません。 (少なくとも基本ケースでは)と同じ出力を生成します。だからここでは役に立たないようです。
script
script -c <command> <logfile><command> > <logfile> 2>&1

答え1

次の機能を使用できます。

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

例:

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

Tim Kennedyが言ったように、非常に便利なscriptコマンドもあります。

$ 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

修正する

リダイレクトとデフォルトですべてのシェル構文も記録する必要がある場合(Command line:実行中のコマンドを簡単に識別するために小さなメッセージを追加しました):

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

eval引用した内容に非常に注意する必要があることを覚えておいてください。

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

1つのコマンドの代わりに同時に複数のコマンドを受け入れることもできます。

$ echo_command 'echo foo' 'echo bar' 'echo baz'
Command line: echo foo
foo
Command line: echo bar
bar
Command line: echo baz
baz

答え2

xtraceシェルのメカニズムを使用して、実行中のコマンドをstdoutとして印刷できます。

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

$PS4気に入らない場合は、デフォルト(ほとんどのシェルで)を"+ "別のものに変更します(接頭辞を望まない場合は空白のままにしてください)。

機能として:

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

log_into out-err.dat ls -l

関連情報