2011-07-06 11 views
6

Tengo un script, que es esencialmente un contenedor alrededor de un ejecutable con el mismo nombre en una máquina diferente. Por el bien de ejemplo, voy a envolver printf aquí. Mi script actual se ve así:Prevenir que ssh rompa los parámetros del script de shell

#!/bin/bash 
ssh [email protected] printf "[email protected]" 

Desafortunadamente, esto se rompe cuando uno de los argumentos contiene un espacio, p. esperaría que los siguientes comandos dieran salidas idénticas .:

~$ ./wrap_printf "%s_%s" "hello world" "1" 
hello_world1_ 
~$ printf "%s_%s" "hello world" "1" 
hello world_1 

El problema empeora cuando se trata de líneas de escape (escapadas). ¿Cómo escapo adecuadamente mis argumentos aquí?

Respuesta

5
#!/bin/sh 
QUOTE_ARGS='' 
for ARG in "[email protected]" 
do 
    QUOTE_ARGS="${QUOTE_ARGS} '${ARG}'" 
done 
ssh [email protected] "${QUOTE_ARGS}" 

Esto funciona para los espacios. No funciona si el argumento tiene una comilla simple incrustada.

+0

Eso funcionará, gracias. Publicaré una respuesta adicional que también corrige el problema de las cotizaciones. – Ondergetekende

7

Sobre la base de la respuesta de Peter Lyons, sino que también permiten cotizaciones dentro de los argumentos:

#!/bin/bash 
QUOTE_ARGS='' 
for ARG in "[email protected]" 
do 
    ARG=$(printf "%q" "$ARG") 
    QUOTE_ARGS="${QUOTE_ARGS} $ARG" 
done 

ssh [email protected] "printf ${QUOTE_ARGS}" 

Esto funciona para todo lo que he probado hasta ahora, excepto los saltos de línea:

$ /tmp/wrap_printf "[-%s-]" "hello'\$t\"" 
[-hello'$t"-] 
+0

Parece que también funciona para líneas nuevas (aunque las líneas nuevas causan otras rarezas de visualización extrañas en las terminales si se muestran en el lugar incorrecto) – Glyph

2

Conseguir citando a la derecha es bastante difícil y hacerlo en bash (de manera general y robusta) es casi imposible.

Uso Perl:

#!/usr/bin/perl 
use Net::OpenSSH; 
my $ssh = Net::OpenSSH->new('[email protected]'); 
$ssh->system('printf', @ARGV); 
0

Sobre la base de las respuestas de Koert y Peter Lyons, aquí un contenedor para ssh; yo lo llamo "sshsystem". (también disponible en https://gist.github.com/4672115)

#!/bin/bash 

# quote command in ssh call to prevent remote side from expanding any arguments 
# uses bash printf %q for quoting - no idea how compatible this is with other shells. 
# http://stackoverflow.com/questions/6592376/prevent-ssh-from-breaking-up-shell-script-parameters 

sshargs=() 

while (($# > 0)); do 
    case "$1" in 
    -[1246AaCfgKkMNnqsTtVvXxYy]) 
     # simple argument 
     sshargs+=("$1") 
     shift 
     ;; 
    -[bcDeFIiLlmOopRSWw]) 
     # argument with parameter 
     sshargs+=("$1") 
     shift 
     if (($# == 0)); then 
      echo "missing second part of long argument" >&2 
      exit 99 
     fi 
     sshargs+=("$1") 
     shift 
     ;; 
    -[bcDeFIiLlmOopRSWw]*) 
     # argument with parameter appended without space 
     sshargs+=("$1") 
     shift 
     ;; 
    --) 
     # end of arguments 
     sshargs+=("$1") 
     shift 
     break 
     ;; 
    -*) 
     echo "unrecognized argument: '$1'" >&2 
     exit 99 
     ;; 
    *) 
     # end of arguments 
     break 
     ;; 
    esac 
done 


# [email protected] 
sshargs+=("$1") 
shift 

# command - quote 
if (($# > 0)); then 
    # no need to make COMMAND an array - ssh will merge it anyway 
    COMMAND= 
    while (($# > 0)); do 
     arg=$(printf "%q" "$1") 
     COMMAND="${COMMAND} ${arg}" 
     shift 
    done 
    sshargs+=("${COMMAND}") 
fi 

exec ssh "${sshargs[@]}" 
Cuestiones relacionadas