2012-09-01 12 views
14

bashを一種の冗長モードにする方法はありますか?シェルスクリプトを実行しているときに実行前に実行するコマンドをエコーし​​ますか?つまり、実行されたコマンド(およびその出力)を見ることができるように、makeの出力に似ていますか? 、私は別の方法として次のような出力Echoコマンドを実行してから実行しますか? (makeのように)

echo "Hello, World" 
Hello, World 

をしたいと思います

echo "Hello, World" 

のようなシェルスクリプトを実行している場合、それはその出力はコマンド意志echo_and_runと呼ばれるbashの関数を作成することも可能です

それを実行しますか?

$ echo_and_run echo "Hello, World" 
echo "Hello, World" 
Hello, World 

答えて

5

それはスペースが保存されるように、引数を逃れるために%q書式指定子と組み合わせてのbashのprintfを使用することが可能です:

function echo_and_run { 
    echo "$" "[email protected]" 
    eval $(printf '%q ' "[email protected]") < /dev/tty 
} 
22

あなたはevalを呼び出す前にechoコマンドに独自の関数を作ることができます。

Bashにはデバッグ機能もあります。 set -xを実行すると、実行前に各コマンドが表示されます。

[email protected]:~/dir$ set -x 
[email protected]:~/dir$ ls 
+ ls --color=auto 
a b c d e f 
+1

1と、 '-x'も殻に行くことができます設定スクリプトの長さが続きます。 – jedwards

+0

これは最高の、最も信頼できるアプローチのようです。 (そしてリダイレクションでもうまくいきますが、私は心配する必要はありませんでしたが、それはうまくいきます)。唯一の問題は、 'set + x'コマンドも出力に現れます。私のスクリプトの行動の記録](http://mywiki.wooledge.org/BashFAQ/050)。 – mjs

+3

@mjs:あなたのスクリプトのランタイム全体をエコーするコマンドを 'bash -x'(' set -x'を暗黙的に有効にし、出力しない)で実行することができます。 –

-1

"echo_and_run"という名前の実行可能な(+ x)​​ベーススクリプトを以下の単純なシェルスクリプトで作成してください!

#!/bin/bash 
echo "$1" 
$1 

$ ./echo_and_run "エコーこんにちは、世界は"

echo Hello, World 
Hello, World 

しかし、set -xcnicutarの approchは、信頼性が高く、強くお勧めします。

+0

いいえ、 'echo" $ @ "; "$ @" ' –

+0

これは引用符をつまらない - 上記の例では、' echo "の代わりに' echo Hello、World'を得ます。 – mjs

+0

"$ @"を使用すると、引用符が呑み込まれます。 './echo_and_run 'echo" Hello、World "' – Mayura

13

ここで何をしたいんシェル関数だ、あなたの質問の後半部分に答えるために:

echo_and_run() { echo "[email protected]" ; "[email protected]" ; } 

私はこれに似たものを使用します。

の前で $を印刷し
echo_and_run() { echo "\$ [email protected]" ; "[email protected]" ; } 

コマンド(シェルプロンプトのように見え、それがコマンドであることを明確にします)。私は、実行中のコマンドのいくつか(ただしすべてではない)を表示したいときにスクリプトでこれを使用することがあります。

他の人が述べたように、それは引用符負けない:

$ echo_and_run echo "Hello, world" 
$ echo Hello, world 
Hello, world 
$ 

を私はそれを避けるために、何か良い方法はないと思います。シェルはecho_and_runの前に引用符を取り除き、それらを見る機会を得ます。スペースや他のシェルメタキャラクタを含む引数をチェックし、必要に応じて引用符を追加するスクリプトを書くことができます(実際に入力した引用符とは必ずしも一致しません)。

+0

1行に複数のコマンドを処理する方法はありますか? 'echo_and_run cd .. && ls'は両方のコマンドを実行しますが、' $ cd .. 'のみを出力します。 – MrTheWalrus

+1

@MrTheWalrus:' cd_'が 'echo_and_run()'関数に引数として渡されるからです。 'echo_and_run cd ..'の後ろに' ls'をタイプするのと同じです。そのトリックは 'echo_and_run' *に単一のコマンド*として送ります:*' echo_and_run sh -c 'cd .. && ls''。 bash固有の機能(またはksh、またはzshなど)が必要な場合は、 '/ bin/sh 'を'/bin/bash'に置き換えてください。 –

+0

ありがとう。私は問題が何であるかを知ることができましたが、その行全体を単一のコマンドとして扱う方法を知らなかった。 – MrTheWalrus

0

他人の実装に追加するには、この引数を含め、私の基本的なスクリプト定型であり、構文解析(冗長レベルを切り替える場合は重要です)。

#!/bin/sh 

# Control verbosity 
VERBOSE=0 

# For use in usage() and in log messages 
SCRIPT_NAME="$(basename $0)" 

ARGS=() 

# Usage function: tells the user what's up, then exits. ALWAYS implement this. 
# Optionally, prints an error message 
# usage [{errorLevel} {message...} 
function usage() { 
    local RET=0 
    if [ $# -gt 0 ]; then 
     RET=$1; shift; 
    fi 
    if [ $# -gt 0 ]; then 
     log "[$SCRIPT_NAME] ${@}" 
    fi 
    log "Describe this script" 
    log "Usage: $SCRIPT_NAME [-v|-q]" # List further options here 
    log " -v|--verbose Be more verbose" 
    log " -q|--quiet  Be less verbose" 
    exit $RET 
} 

# Write a message to stderr 
# log {message...} 
function log() { 
    echo "${@}" >&2 
} 

# Write an informative message with decoration 
# info {message...} 
function info() { 
    if [ $VERBOSE -gt 0 ]; then 
     log "[$SCRIPT_NAME] ${@}" 
    fi 
} 

# Write an warning message with decoration 
# warn {message...} 
function warn() { 
    if [ $VERBOSE -gt 0 ]; then 
     log "[$SCRIPT_NAME] Warning: ${@}" 
    fi 
} 

# Write an error and exit 
# error {errorLevel} {message...} 
function error() { 
    local LEVEL=$1; shift 
    if [ $VERBOSE -gt -1 ]; then 
     log "[$SCRIPT_NAME] Error: ${@}" 
    fi 
    exit $LEVEL 
} 

# Write out a command and run it 
# vexec {minVerbosity} {prefixMessage} {command...} 
function vexec() { 
    local LEVEL=$1; shift 
    local MSG="$1"; shift 
    if [ $VERBOSE -ge $LEVEL ]; then 
     echo -n "$MSG: " 
     local CMD=() 
     for i in "${@}"; do 
      # Replace argument's spaces with ''; if different, quote the string 
      if [ "$i" != "${i/ /}" ]; then 
       CMD=(${CMD[@]} "'${i}'") 
      else 
       CMD=(${CMD[@]} $i) 
      fi 
     done 
     echo "${CMD[@]}" 
    fi 
    ${@} 
} 

# Loop over arguments; we'll be shifting the list as we go, 
# so we keep going until $1 is empty 
while [ -n "$1" ]; do 
    # Capture and shift the argument. 
    ARG="$1" 
    shift 
    case "$ARG" in 
     # User requested help; sometimes they do this at the end of a command 
     # while they're building it. By capturing and exiting, we avoid doing 
     # work before it's intended. 
     -h|-\?|-help|--help) 
      usage 0 
      ;; 
     # Make the script more verbose 
     -v|--verbose) 
      VERBOSE=$((VERBOSE + 1)) 
      ;; 
     # Make the script quieter 
     -q|--quiet) 
      VERBOSE=$((VERBOSE - 1)) 
      ;; 
     # All arguments that follow are non-flags 
     # This should be in all of your scripts, to more easily support filenames 
     # that start with hyphens. Break will bail from the `for` loop above. 
     --) 
      break 
      ;; 
     # Something that looks like a flag, but is not; report an error and die 
     -?*) 
      usage 1 "Unknown option: '$ARG'" >&2 
      ;; 
     # 
     # All other arguments are added to the ARGS array. 
     *) 
      ARGS=(${ARGS[@]} "$ARG") 
      ;; 
    esac 
done 
# If the above script found a '--' argument, there will still be items in $*; 
# move them into ARGS 
while [ -n "$1" ]; do 
    ARGS=(${ARGS[@]} "$1") 
    shift 
done 

# Main script goes here. 

その後...

vexec 1 "Building myapp.c" \ 
    gcc -c myapp.c -o build/myapp.o ${CFLAGS} 

注:これは、パイプされたコマンドをカバーしません。あなたはそれらの種類のものをbashするか、中間変数やファイルに分割する必要があります。スクリプトまたは対話型セッションでbashコマンドラインにまたはsetコマンドを介して追加することができ

0

ている便利なシェルオプション:

  • -vプリントシェル入力行が読み取られるよう。
  • -x
  • コマンドとその拡張 引数または関連単語リストに続く各単純なコマンド、 forコマンド、 caseコマンド、 selectコマンド、または算術 forコマンド、表示 PS4の拡大値を、展開した後。余分なタイムスタンプとI/O情報については
0

Debianのさんdevscriptsパッケージからannotate-outputコマンドを考慮すると:

annotate-output echo hello 

出力:

13:19:08 I: Started echo hello 
13:19:08 O: hello 
13:19:08 I: Finished with exitcode 0 

は今見てが存在しないファイルの場合、およびEの点に注意してください。 STDERR用出力:

annotate-output ls nosuchfile 

出力:それは明白でなければ、また

13:19:48 I: Started ls nosuchfile 
13:19:48 E: ls: cannot access 'nosuchfile': No such file or directory 
13:19:48 I: Finished with exitcode 2 
関連する問題