Pasar una cadena con espacios como argumento de función en bash

173

Estoy escribiendo un script bash donde necesito pasar una cadena que contiene espacios a una función en mi script bash.

Por ejemplo:

#!/bin/bash

myFunction
{
    echo $1
    echo $2
    echo $3
}

myFunction "firstString" "second string with spaces" "thirdString"

Cuando se ejecuta, el resultado que esperaría es:

firstString
second string with spaces
thirdString

Sin embargo, lo que realmente sale es:

firstString
second
string

¿Hay alguna manera de pasar una cadena con espacios como argumento único a una función en bash?

Grant Limberg
fuente
Funciona para mí ... Utilizo la sintaxis completa para las funciones, aunque "function bla () {echo $ 1;}", no puede hacer que uno corto se convierta en un trazador de líneas. No estoy seguro de que haga la diferencia. ¿Qué versión de bash?
Eugene
8
intente echo "$@"o for i in "$@"; do echo $i ; donepara usar parámetros correctamente citados que contienen espacios. Este es el muy claramente mencionado en toda la bashdocumentación en la positional parameterssección.
Samveen
1
Estaba teniendo un problema similar, tratando de pasar una cadena entre comillas como parámetro y solo la primera palabra de la cadena se reconoce como parte del parámetro. La sugerencia de Samveen de cambiar $ 1 a $ @ funcionó para mí. Tenga en cuenta que solo estaba pasando un parámetro a la función, pero si hubiera pasado más usando la instrucción for habría sido necesario.
Erin Geyer
Consulte también stackoverflow.com/questions/10067266/…
tripleee
1
intentar myFunction "$@"
vimjet

Respuestas:

176

debe poner comillas y también, su declaración de función es incorrecta.

myFunction()
{
    echo "$1"
    echo "$2"
    echo "$3"
}

Y como los demás, también funciona para mí. Díganos qué versión de shell está utilizando.

ghostdog74
fuente
3
Esto funciona muy bien para mí también. Si estamos llamando a otra función dentro de myFunction, entonces pase argumentos con comillas. Saludos :)
minhas23
2
¿Puedes explicar por qué uno necesita citas? Intenté con y sin, y no funcionó para mí. Estoy usando Ubuntu 14.04, GNU bash, versión 4.3.11 (1) -release (x86_64-pc-linux-gnu). Lo que funciona para mí es usar $ @ (con o sin comillas).
Kyle Baker, el
@KyleBaker, sin las comillas, se $@comporta como sin comillas $*: los resultados se dividen en cadenas y luego se expanden individualmente de forma global, por lo que si tiene pestañas, se convertirán en espacios, si tiene palabras que pueden evaluarse como expresiones globales. será, etc.
Charles Duffy
17

Otra solución al problema anterior es establecer cada cadena en una variable, llamar a la función con variables denotadas por un signo de dólar literal \$. Luego, en la función, use evalpara leer la variable y la salida como se esperaba.

#!/usr/bin/ksh

myFunction()
{
  eval string1="$1"
  eval string2="$2"
  eval string3="$3"

  echo "string1 = ${string1}"
  echo "string2 = ${string2}"
  echo "string3 = ${string3}"
}

var1="firstString"
var2="second string with spaces"
var3="thirdString"

myFunction "\${var1}" "\${var2}" "\${var3}"

exit 0

La salida es entonces:

    string1 = firstString
    string2 = second string with spaces
    string3 = thirdString

Al tratar de resolver un problema similar a este, me encontraba con el problema de UNIX pensando que mis variables estaban delimitadas por espacios. Intenté pasar una cadena delimitada por una tubería a una función awkpara establecer una serie de variables que luego se usaron para crear un informe. Inicialmente probé la solución publicada por ghostdog74 pero no pude hacer que funcionara ya que no todos mis parámetros se pasaban entre comillas. Después de agregar comillas dobles a cada parámetro, comenzó a funcionar como se esperaba.

A continuación se muestra el estado anterior de mi código y el estado posterior completamente funcional.

Antes - Código no funcional

#!/usr/bin/ksh

#*******************************************************************************
# Setup Function To Extract Each Field For The Error Report
#*******************************************************************************
getField(){
  detailedString="$1"
  fieldNumber=$2

  # Retrieves Column ${fieldNumber} From The Pipe Delimited ${detailedString} 
  #   And Strips Leading And Trailing Spaces
  echo ${detailedString} | awk -F '|' -v VAR=${fieldNumber} '{ print $VAR }' | sed 's/^[ \t]*//;s/[ \t]*$//'
}

while read LINE
do
  var1="$LINE"

  # Below Does Not Work Since There Are Not Quotes Around The 3
  iputId=$(getField "${var1}" 3)
done<${someFile}

exit 0

Después - Código de funcionamiento

#!/usr/bin/ksh

#*******************************************************************************
# Setup Function To Extract Each Field For The Report
#*******************************************************************************
getField(){
  detailedString="$1"
  fieldNumber=$2

  # Retrieves Column ${fieldNumber} From The Pipe Delimited ${detailedString} 
  #   And Strips Leading And Trailing Spaces
  echo ${detailedString} | awk -F '|' -v VAR=${fieldNumber} '{ print $VAR }' | sed 's/^[ \t]*//;s/[ \t]*$//'
}

while read LINE
do
  var1="$LINE"

  # Below Now Works As There Are Quotes Around The 3
  iputId=$(getField "${var1}" "3")
done<${someFile}

exit 0
TheBanjoMinnow
fuente
7

La solución más simple a este problema es que solo necesita usar \"argumentos separados por espacios al ejecutar un script de shell:

#!/bin/bash
myFunction() {
  echo $1
  echo $2
  echo $3
}
myFunction "firstString" "\"Hello World\"" "thirdString"
Piyush Aggarwal
fuente
5

Su definición de myFunction es incorrecta. Debería ser:

myFunction()
{
    # same as before
}

o:

function myFunction
{
    # same as before
}

De todos modos, se ve bien y funciona bien para mí en Bash 3.2.48.

R Samuel Klatchko
fuente
5

Llego 9 años tarde pero una forma más dinámica sería

function myFunction {
   for i in "$*"; do echo "$i"; done;
}
remykarem
fuente
2
Ah genial! Esto es exactamente lo que estaba buscando durante algún tiempo en muchas preguntas. ¡Gracias!
prosoitos
2

Solución simple que funcionó para mí: cotizado $ @

Test(){
   set -x
   grep "$@" /etc/hosts
   set +x
}
Test -i "3 rb"
+ grep -i '3 rb' /etc/hosts

Pude verificar el comando grep real (gracias a set -x).

Bin TAN - Victor
fuente
-1

Podría tener una extensión de este problema en caso de que su texto inicial se haya configurado en una variable de tipo de cadena, por ejemplo:

function status(){    
  if [ $1 != "stopped" ]; then
     artist="ABC";
     track="CDE";
     album="DEF";
     status_message="The current track is $track at $album by $artist";
     echo $status_message;
     read_status $1 "$status_message";
  fi
}

function read_status(){
  if [ $1 != "playing" ]; then
    echo $2
  fi
}

En este caso, si no pasa la variable status_message hacia adelante como una cadena (rodeada por ""), se dividirá en un conjunto de argumentos diferentes.

"$ variable" : la pista actual es CDE en DEF por ABC

$ variable : El

helmedeiros
fuente
OP usado myFunction "firstString" "second string with spaces" "thirdString"y no funcionó para él. Entonces, lo que usted propone no se aplica a esta pregunta.
doubleDown
-2

Tenía el mismo tipo de problema y, de hecho, el problema no era la función ni la llamada a la función, sino lo que le pasé como argumentos a la función.

La función se llamó desde el cuerpo del script, el 'principal', así que pasé "st1 a b" "st2 c d" "st3 e f" desde la línea de comandos y la pasé a la función usando myFunction $ *

$ * Causa el problema a medida que se expande en un conjunto de caracteres que se interpretarán en la llamada a la función utilizando espacios en blanco como delimitador.

La solución fue cambiar la llamada a la función en el manejo explícito de argumentos desde el 'principal' hacia la función: la llamada sería myFunction "$ 1" "$ 2" "$ 3" que preservará el espacio en blanco dentro de las cadenas ya que las comillas delimitarán los argumentos ... Entonces, si un parámetro puede contener espacios, debe manejarse explícitamente en todas las llamadas de funciones.

Como esta puede ser la razón de las largas búsquedas de problemas, puede ser aconsejable nunca usar $ * para pasar argumentos ...

Espero que esto ayude a alguien, algún día, en algún lugar ... Jan.

ene
fuente
La respuesta correcta es "$@", no todos citado "$1", "$2", ... parametros posicionales ni $*.
Samveen