Passare una stringa con spazi come argomento di funzione in bash


173

Sto scrivendo uno script bash in cui devo passare una stringa contenente spazi a una funzione nel mio script bash.

Per esempio:

#!/bin/bash

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

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

Quando eseguito, l'output che mi aspetto è:

firstString
second string with spaces
thirdString

Tuttavia, ciò che effettivamente viene prodotto è:

firstString
second
string

C'è un modo per passare una stringa con spazi come singolo argomento a una funzione in bash?


Funziona per me ... Uso la sintassi completa per le funzioni sebbene "function bla () {echo $ 1;}", non riesco a farne una breve in una riga. Non sono sicuro che faccia la differenza. Quale versione di bash?
Eugene,

8
provare echo "$@"o for i in "$@"; do echo $i ; doneper utilizzare i parametri correttamente quotati contenenti spazi. Questo è chiaramente menzionato in tutta la bashdocumentazione nella positional parameterssezione.
Samveen,

1
Stavo avendo un problema simile, provando a passare una stringa tra virgolette come parametro e solo la prima parola della stringa viene riconosciuta come parte del parametro. Il suggerimento di Samveen di cambiare $ 1 in $ @ ha funzionato per me. Nota che stavo solo passando un parametro alla funzione, ma se avessi passato più parametri usando l'istruzione for sarebbe stato necessario.
Erin Geyer,


1
provare myFunction "$@"
vimjet,

Risposte:


176

dovresti inserire delle virgolette e anche la tua dichiarazione di funzione è sbagliata.

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

E come gli altri, funziona anche per me. Dicci quale versione di shell stai usando.


3
Questo funziona molto bene anche per me. Se stiamo chiamando un'altra funzione all'interno di myFunction, passa gli argomenti tra virgolette. Saluti :)
minhas23,

2
Puoi spiegare perché è necessario un preventivo? Ho provato sia con che senza, e non ha funzionato per me. Sto usando Ubuntu 14.04, GNU bash, versione 4.3.11 (1) -release (x86_64-pc-linux-gnu). Quello che funziona per me è usare $ @ (con o senza virgolette).
Kyle Baker,

@KyleBaker, senza virgolette, $@si comporta proprio come non quotato $*: i risultati vengono suddivisi in stringhe e quindi espansi singolarmente a livello globale, quindi se hai delle schede verranno convertiti in spazi, se hai parole che possono essere valutate come espressioni glob loro sarà, ecc.
Charles Duffy,

17

Un'altra soluzione al problema sopra è impostare ogni stringa su una variabile, chiamare la funzione con variabili indicate da un segno di dollaro letterale \$. Quindi nella funzione utilizzare evalper leggere la variabile e produrre come previsto.

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

L'output è quindi:

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

Nel tentativo di risolvere un problema simile a questo, stavo incontrando il problema di UNIX pensando che le mie variabili fossero delimitate da spazio. Stavo cercando di passare una stringa delimitata da pipe a una funzione utilizzando awkper impostare una serie di variabili successivamente utilizzate per creare un report. Inizialmente ho provato la soluzione pubblicata da ghostdog74 ma non sono riuscito a farlo funzionare poiché non tutti i miei parametri venivano passati tra virgolette. Dopo aver aggiunto virgolette doppie a ciascun parametro, ha iniziato a funzionare come previsto.

Di seguito è riportato lo stato precedente del mio codice e pienamente funzionante dopo lo stato.

Prima - Codice non funzionante

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

Codice After - Functioning

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

7

La soluzione più semplice a questo problema è che devi solo usare \"argomenti separati dallo spazio quando esegui uno script shell:

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

5

La tua definizione di myFunction è errata. Dovrebbe essere:

myFunction()
{
    # same as before
}

o:

function myFunction
{
    # same as before
}

Comunque, sembra buono e funziona bene per me su Bash 3.2.48.


5

Sono in ritardo di 9 anni, ma sarebbe un modo più dinamico

function myFunction {
   for i in "$*"; do echo "$i"; done;
}

2
Ah fantastico! questo è esattamente quello che stavo cercando da tempo su molte domande. Grazie!
prosoitos,

2

Soluzione semplice che ha funzionato per me - citato $ @

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

Ho potuto verificare l'attuale comando grep (grazie a set -x).


-1

Potresti avere un'estensione di questo problema nel caso in cui il tuo testo iniziale fosse impostato in una variabile di tipo stringa, ad esempio:

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
}

In questo caso, se non si passa la variabile status_message in avanti come stringa (racchiusa da ""), verrà suddivisa in una serie di argomenti diversi.

"$ variabile" : la traccia corrente è CDE presso DEF di ABC

$ variabile : il


OP ha usato myFunction "firstString" "second string with spaces" "thirdString"e non ha funzionato per lui. Quindi ciò che proponi non si applica a questa domanda.
doubleDown

-2

Aveva lo stesso tipo di problema e in effetti il ​​problema non era la funzione né la chiamata della funzione, ma ciò che ho passato come argomenti alla funzione.

La funzione è stata chiamata dal corpo dello script - il 'principale' - quindi ho passato "st1 a b" "st2 c d" "st3 e f" dalla riga di comando e l'ho passato alla funzione usando myFunction $ *

$ * Causa il problema in quanto si espande in una serie di caratteri che verranno interpretati nella chiamata alla funzione utilizzando gli spazi bianchi come delimitatore.

La soluzione era quella di cambiare la chiamata alla funzione nella gestione esplicita degli argomenti da 'main' verso la funzione: la chiamata sarebbe quindi myFunction "$ 1" "$ 2" "$ 3" che conserverà lo spazio bianco all'interno delle stringhe mentre le virgolette delimiteranno gli argomenti ... Quindi se un parametro può contenere spazi, dovrebbe essere gestito in modo esplicito in tutte le chiamate di funzioni.

Poiché questo potrebbe essere il motivo di lunghe ricerche di problemi, potrebbe essere saggio non usare mai $ * per passare argomenti ...

Spero che questo aiuti qualcuno, un giorno, da qualche parte ... Jan.


La risposta corretta è "$@", non tutti citato "$1", "$2", ... paramters posizionali né $*.
Samveen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.