2009-10-12 14 views
7

Me enfrenta un pequeño problema aquí, quiero pasar una cadena que contiene espacios en blanco, a otro programa de modo que toda la cadena se trata como un argumento de línea de comando.Preservar espacios en blanco en una cadena como un argumento de línea de comando

En pocas palabras, quiere ejecutar un comando de la siguiente estructura a través de un script de shell bash: command_name -a -b arg1 arg2 -c "arg con espacios en blanco aquí"

Pero no importa cuanto lo intento, la los espacios en blanco no se conservan en la cadena y se tokenizan de forma predeterminada. Una solución favor,

edición: Esta es la parte principal de mi guión:

#!/bin/bash 

#-------- BLACKRAY CONFIG ---------------# 
# Make sure the current user is in the sudoers list 
# Running all instances with sudo 

BLACKRAY_BIN_PATH='/opt/blackray/bin' 
BLACKRAY_LOADER_DEF_PATH='/home/crozzfire' 
BLACKRAY_LOADER_DEF_NAME='load.xml' 
BLACKRAY_CSV_PATH='/home/crozzfire' 
BLACKRAY_END_POINT='default -p 8890' 
OUT_FILE='/tmp/out.log' 

echo "The current binary path is $BLACKRAY_BIN_PATH" 


# Starting the blackray 0.9.0 server 
sudo "$BLACKRAY_BIN_PATH/blackray_start" 

# Starting the blackray loader utility 
BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "\"$BLACKRAY_END_POINT\""" 

sudo time $BLACKRAY_INDEX_CMD -a $OUT_FILE 

#--------- END BLACKRAY CONFIG ---------# 
+0

Lo sentimos, pero usted ha proporcionado muy poca información. ¿Qué shell usas (bash, ksh, csh, ...)? ¿Puedes decir qué comando intentas ejecutar? Si se trata de una utilidad UNIX estándar, ¿puede decir su versión? –

+0

script bash. La autorización aquí es lo que estoy tratando de hacer: .... BLACKRAY_END_POINT = "default -p 8890" .... CMD = "$ BLACKRAY_BIN_PATH/blackray_loader -C $ BLACKRAY_LOADER_DEF_PATH/$ BLACKRAY_LOADER_DEF_NAME -d $ BLACKRAY_CSV_PATH - e \ "$ BLACKRAY_END_POINT \" " ... Ahora quiero ejecutar el comando anterior de manera que $ BLACKRAY_END_POINT se trate como una sola cadena y no se convierta en tokenizado. $ BLACKRAY_END_POINT es una cadena que contiene espacios y bash la divide en diferentes palabras. Quiero preservar los espacios y pasar toda la cadena como un único argumento. – crozzfire

+0

Desconocido, meet backslash-double-quote (\ "). Backslash-double-quote, meet unknown. –

Respuesta

1

probablemente usted tiene que rodear el argumento entre comillas dobles (por ejemplo, "$ {6}").

siguiente comentario OP debe ser "$ BLACKRAY_END_POINT"

+0

Probado. Pero todavía toma solo" default "y no toda la cadena :( – crozzfire

+0

Reemplace -e \" $ BLACKRAY_END_POINT \ "" a "\" $ BLACKRAY_END_POINT \ "". Necesita "" para escapar de espacios en su secuencia de comandos y adicional \ "\" para escapar espacios cuando se ejecuta el comando – dimba

+0

todavía no tiene suerte, se necesita -> "predeterminado como arg now (comillas extra abiertas). Para ejecutar estoy usando: sudo time $ CMD -a $ OUT_FILE. Si reemplazo $ CMD como "$ CMD", me da un error de archivo o directorio. – crozzfire

1

Editar:

Probar:

BLACKRAY_END_POINT="'default -p 8890'" 

o

BLACKRAY_END_POINT='"default -p 8890"' 

o

BLACKRAY_END_POINT="default\ -p\ 8890" 

o

BLACKRAY_END_POINT='default\ -p\ 8890' 

y

BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e $BLACKRAY_END_POINT" 

Respuesta original:

Es blackray_loader un script de shell?

Aquí es una demostración de que usted tiene que hacer frente a este problema, tanto cuando se especifica el parámetro y en su manipulación:

Un archivo de texto llamado "test.txt" (incluya los números de línea):

1 two words 
2 two  words 
3 two 
4 words 

un script llamado "spacetest":

#!/bin/bash 
echo "No quotes in script" 
echo $1 
grep $1 test.txt 
echo 

echo "With quotes in script" 
echo "$1" 
grep "$1" test.txt 
echo 

Correr con ./spacetest "two--------words" (reemplace los guiones con espacios):

No quotes in script 
two words 
grep: words: No such file or directory 
test.txt:1 two words 
test.txt:2 two  words 
test.txt:3 two 

With quotes in script 
two  words 
2 two  words 

Se puede ver que en la sección "sin comillas" se trató de hacer grep two words test.txt, que interpreta "palabras" como nombre de archivo, además de "test.txt". Además, el echo dejó caer los espacios adicionales.

Cuando se cita el parámetro, como en la segunda sección, grep lo vio como un argumento (incluidos los espacios adicionales) y lo manejó correctamente. Y echo preservaron los espacios adicionales.

Usé los espacios adicionales, por cierto, simplemente para ayudar en la demostración.

+0

Estoy de acuerdo. Pero en En mi caso, no estoy pasando ningún argumento al script bash, sino que estoy hardcoding un argumento (con espacios) que necesita pasar a un comando. Este comando (blackray_loader) se llama con mi script bash. Solo necesito para preservar los espacios en blanco del argumento y pasarlo como una cadena completa. – crozzfire

+0

Eso es exactamente lo que estoy demostrando. En el script de arriba, 'grep' es un sustituto de' blackray_loader'. Su comando necesitará manejar adecuadamente los parámetros. Sin embargo, vea la edición para probar otra cosa. –

5

Te encuentras con este problema porque almacenas el comando en una variable y luego lo expandes más tarde; a menos que haya una buena razón para hacer esto, No:

sudo time $BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT" -a $OUT_FILE 

Si realmente no necesita almacenar el comando y utilizarlo más adelante, hay varias opciones; la wiki de bash-hackers.org tiene un good page on the subject. A mi me parece como la más útil aquí es poner el comando en una matriz en lugar de una variable simple:

BLACKRAY_INDEX_CMD=($BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT") 

sudo time "${BLACKRAY_INDEX_CMD[@]}" -a $OUT_FILE 

Esto evita toda la confusión entre los espacios de separación de Palabras y espacios dentro de otras palabras, porque las palabras no están separados por espacios; están en elementos separados de la matriz. La expansión de la matriz entre comillas dobles con el sufijo [@] conserva esa estructura.

(Por cierto, otra opción sería utilizar comillas escapadas vez que estás haciendo, a continuación, ejecutar el comando con eval No haga esto;.. Que es una buena manera de introducir el análisis de errores extraños)

3

tengo una sugerencia:

# iterate through the passed arguments, save them to new properly quoted ARGS string 
while [ -n "$1" ]; do 
    ARGS="$ARGS '$1'" 
    shift 
done 

# invoke the command with properly quoted arguments 
my_command $ARGS 
+3

Esto no funciona en absoluto: el shell analiza las comillas antes de expandir las variables, de modo que si hay comillas en los valores de la variable, no se tratan como comillas, solo como caracteres normales. Básicamente, es demasiado tarde para que tengan el efecto deseado. Lo que realmente ocurre es que pasan al comando como parte del argumento, que no es lo que quieres. –

-1

un post en otro blog me salvó espacios en blanco para este problema: http://logbuffer.wordpress.com/2010/09/23/bash-scripting-preserve-whitespaces-in-variables/

por defecto, los espacios en blanco se Trimed:

bash> VAR1="abc  def gh ijk" 
bash> echo $VAR1 
abc def gh ijk 
bash> 

"La causa de este comportamiento es la variable de shell interna $ IFS (Separador interno de campos), que tiene como valor predeterminado espacios en blanco, tabulador y nueva línea. Para preservar todos los espacios en blanco contiguos usted tiene que fijar el IFS a algo diferente "

Con IFS de derivación:

bash> IFS='%' 
bash> echo $VAR1 
abc  def gh ijk 
bash>unset IFS 
bash> 

Funciona de maravilla para mi caso comando:

su - user1 -c 'test -r "'${filepath}'"; ....' 

Espero que esto ayude.

+0

Deje de propagar hacks retardados, por favor. Está demostrando claramente que no comprende la importancia de las comillas. _Por defecto, los espacios en blanco están trimed_: INCORRECTO. Sin comillas, vas por debajo de división de palabras y expansiones de nombre de archivo. Cura esto con comillas: 'VAR1 =" abc def gh ijk "; echo "$ VAR1" '. Ahora funciona. Además, ¿cómo explicarías qué sucede en el caso de un comodín: 'VAR1 = '*'; echo $ VAR1' vs 'VAR1 = '*'; echo "$ VAR1" '? Incluso con su cosa 'IFS', obtendrá el mismo resultado horrible:' IFS =%; VAR1 = '*'; echo $ VAR1'. Solo usa más comillas. Período. –

+0

¿Puede explicarme por qué se enruta filepath en este caso: 'test -r "' $ {filepath} '"'? – Kloe2378231

+0

Tienes que entender cómo funcionan las cotizaciones. No hay anidamientos para las comillas. Tomaré su comando completo: 'su - user1 -c 'test -r"' $ {filepath} '";' '. Si 'filepath' contiene espacios, por ej.,' Filepath = 'a b'', cuando hagas 'su - user1 -c' test -r" '$ {filepath}' "; '', bash se expandirá a la siguiente palabras: 'su',' -', 'user1',' -c', 'test -r" a', 'b"; '. No es lo que quieres Con 'IFS =%' es _seems_ que funciona, pero fallará si 'filepath' contiene comodines o el símbolo'% 'o el símbolo' "' (u otros comodines). –

0

A continuación está mi ejemplo le de reiniciar un script a través de exec su USER o exec su - USER. Tiene capacidad para:

  • ser llamado desde una ruta relativa o directorio de trabajo actual
  • espacios en nombre del script y argumentos
  • individual y comillas dobles en argumentos, sin escapes locas como: \\"

# 
# This script should always be run-as a specific user 
# 
user=jimbob 
if [ $(whoami) != "$user" ]; then 
    exec su -c "'$(readlink -f "$0")' $(printf " %q" "[email protected]")" - $user 
    exit $? 
fi 
Cuestiones relacionadas