2012-09-01 17 views
14

¿Hay alguna forma de hacer que bash se mueva a un tipo de modo detallado donde, de modo que, cuando se ejecuta un script de shell, se repita el comando que se va a ejecutar antes de ejecutarlo? Es decir, ¿para que sea posible ver los comandos que se ejecutaron (así como su salida), similar a la salida de make?Echo comando, y luego ejecutarlo? (Como make)

Es decir, si se ejecuta un script de shell como

echo "Hello, World" 

Me gustaría que la siguiente salida

echo "Hello, World" 
Hello, World 

Alternativamente, es posible escribir una función de bash llamado echo_and_run que es la salida de un comando y luego ejecutarlo?

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

Respuesta

5

Es posible utilizar fiesta de printf en conjunto con el %q especificador de formato para escapar de los argumentos de manera que los espacios se preservan:

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

Se podría hacer su propia función para echo comandos antes de llamar eval.

Bash también tiene una función de depuración. Una vez que set -x bash mostrará cada comando antes de ejecutarlo.

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

+1 y también, si no es obvio, 'set -x' También se puede ir con cáscara scripts y durará la longitud del script. – jedwards

+0

Este parece ser el mejor y más confiable enfoque. (Y también funciona con la redirección, que estaba preparado para no preocuparme, aunque es bueno tenerlo). El único problema es que los comandos 'set + x' también aparecen en la salida ... También descubrí esto: [Quiero un registro de las acciones de mi script] (http://mywiki.wooledge.org/BashFAQ/050). – mjs

+3

@mjs: si desea que el comando emita un eco durante todo el tiempo de ejecución de su script, puede ejecutarlo a través de 'bash -x' (que habilita' set -x' implícitamente y no lo genera). –

-1

Crear script ejecutable (+ x) base llamado "echo_and_run" con el script de shell simple mencionado a continuación!

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

$ ./echo_and_run "echo Hola, mundo"

echo Hello, World 
Hello, World 

Sin embargo, approch de cnicutar a set -x es fiable y muy recomendable.

+0

No, do 'echo" $ @ "; "$ @" ' –

+0

Esto traga citas - para el ejemplo de arriba, obtienes' echo Hello, World' en lugar de 'echo" Hello, World "'. – mjs

+0

Correcto, si usamos "$ @", se traga las comillas. uno puede usar algo como, './echo_and_run 'echo" Hola, Mundo "' ' – Mayura

13

Para responder a la segunda parte de su pregunta, he aquí una función de shell que hace lo que quiere:

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

que utiliza algo similar a esto:

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

que imprime $ frente el comando (se ve como un mensaje de comandos de shell y lo hace más claro que es un comando). A veces uso esto en scripts cuando quiero mostrar algunos (pero no todos) los comandos que está ejecutando.

Como otros han mencionado, que hace perder las comillas:

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

pero no creo que haya ninguna buena manera de evitar eso; las comillas tiras comillas antes de echo_and_run tiene la oportunidad de verlas. Podría escribir un script que verifique los argumentos que contienen espacios y otros metacaracteres del shell y agregue comillas según sea necesario (que aún no coincidiría necesariamente con las comillas que escribió).

+0

¿Hay alguna manera de hacer que este maneje varios comandos en una sola línea? Es decir, 'echo_and_run cd .. && ls' ejecuta ambos comandos, pero solo produce' $ cd ..' – MrTheWalrus

+1

@MrTheWalrus: Eso es porque solo 'cd ..' se pasa como argumentos a la función' echo_and_run() '. Es como escribir 'echo_and_run cd ..' seguido de' ls'. El truco es alimentarlo a 'echo_and_run' * como un solo comando *:' echo_and_run sh -c 'cd .. && ls''. Reemplace '/ bin/sh' por'/bin/bash' si necesita funciones específicas de bash (o ksh, o zsh, o ...) –

+0

Gracias. Pude ver cuál era el problema, pero no tenía idea de cómo hacerlo para tratar toda la línea como un solo comando. – MrTheWalrus

0

Para agregar a las implementaciones de los demás, esta es mi texto modelo básico de escritura, incluyendo el argumento análisis (que es importante si está cambiando los niveles de verbosidad).

#!/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. 

tarde ...

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

Nota: Esto no va a cubrir los comandos de tuberías; necesita bash -c ese tipo de cosas, o dividirlas en variables intermedias o archivos.

0

Dos opciones útiles de concha que se pueden añadir a la línea de comandos o bash a través del comando set en un script o sesión interactiva:

  • -v impresión de concha líneas de entrada a medida que se leen.
  • -x Después de la expansión de cada comando simple, for de comandos, comandos case, select comando o comandos aritmética for, pantalla el valor expandido de PS4, seguido por el comando y sus argumentos expandidos o lista de palabras asociado.
0

Por marcas de tiempo adicionales y E/S información, considere el comando annotate-output de Debian 's devscripts paquete:

annotate-output echo hello 

Salida:

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

Ahora mira para un archivo que no existe, y tenga en cuenta la E: para STDERR de salida:

annotate-output ls nosuchfile 

Salida:

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 
Cuestiones relacionadas