Übergeben einer Zeichenfolge mit Leerzeichen als Funktionsargument in bash

173

Ich schreibe ein Bash-Skript, in dem ich eine Zeichenfolge mit Leerzeichen an eine Funktion in meinem Bash-Skript übergeben muss.

Beispielsweise:

#!/bin/bash

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

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

Beim Ausführen würde ich folgende Ausgabe erwarten:

firstString
second string with spaces
thirdString

Was jedoch tatsächlich ausgegeben wird, ist:

firstString
second
string

Gibt es eine Möglichkeit, eine Zeichenfolge mit Leerzeichen als einzelnes Argument an eine Funktion in bash zu übergeben?

Grant Limberg
quelle
Funktioniert für mich ... Ich verwende die vollständige Syntax für Funktionen, obwohl "function bla () {echo $ 1;}" keine kurze in einen Einzeiler verwandeln kann. Ich bin mir nicht sicher, ob es einen Unterschied macht. Welche Version von Bash?
Eugene
8
versuchen Sie es echo "$@"oder for i in "$@"; do echo $i ; doneverwenden Sie korrekt zitierte Parameter, die Leerzeichen enthalten. Dies ist die in allen bashDokumentationen unter positional parametersAbschnitt sehr deutlich erwähnte .
Samveen
1
Ich hatte ein ähnliches Problem, als ich versuchte, eine Zeichenfolge in Anführungszeichen als Parameter zu übergeben und nur das erste Wort der Zeichenfolge als Teil des Parameters zu erkennen. Samveens Vorschlag, $ 1 in $ @ zu ändern, hat bei mir funktioniert. Beachten Sie, dass ich nur einen Parameter an die Funktion übergeben habe, aber wenn ich mehr mit der for-Anweisung übergeben hätte, wäre dies notwendig gewesen.
Erin Geyer
1
versuchen myFunction "$@"
vimjet

Antworten:

176

Sie sollten Anführungszeichen setzen und außerdem ist Ihre Funktionsdeklaration falsch.

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

Und wie die anderen funktioniert es auch bei mir. Sagen Sie uns, welche Version der Shell Sie verwenden.

Ghostdog74
quelle
3
Das funktioniert auch bei mir sehr gut. Wenn wir eine andere Funktion in myFunction aufrufen, übergeben Sie Argumente mit Anführungszeichen. Prost :)
minhas23
2
Können Sie erklären, warum man Zitate braucht? Ich habe es sowohl mit als auch ohne versucht, und es hat bei mir nicht funktioniert. Ich verwende Ubuntu 14.04, GNU Bash, Version 4.3.11 (1) -Veröffentlichung (x86_64-pc-linux-gnu). Was tut Arbeit für mich ist $ mit @ (mit oder ohne Anführungszeichen).
Kyle Baker
@KyleBaker $@verhält sich ohne Anführungszeichen wie ohne Anführungszeichen. Die $*Ergebnisse werden in Zeichenfolgen aufgeteilt und dann einzeln global erweitert. Wenn Sie also Registerkarten haben, werden diese in Leerzeichen konvertiert, wenn Sie Wörter haben, die als globale Ausdrücke ausgewertet werden können wird sein, etc.
Charles Duffy
17

Eine andere Lösung für das obige Problem besteht darin, jede Zeichenfolge auf eine Variable zu setzen und die Funktion mit Variablen aufzurufen, die durch ein Literal-Dollarzeichen gekennzeichnet sind \$. Verwenden Sie dann in der Funktion eval, um die Variable zu lesen und wie erwartet auszugeben.

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

Die Ausgabe ist dann:

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

Bei dem Versuch, ein ähnliches Problem zu lösen, stieß ich auf das Problem von UNIX, weil ich dachte, meine Variablen seien durch Leerzeichen getrennt. Ich habe versucht, eine durch Pipe getrennte Zeichenfolge mit an eine Funktion zu übergebenawk zu übergeben, um eine Reihe von Variablen festzulegen, die später zum Erstellen eines Berichts verwendet wurden. Ich habe zunächst die von Ghostdog74 veröffentlichte Lösung ausprobiert, konnte sie jedoch nicht zum Laufen bringen, da nicht alle meine Parameter in Anführungszeichen übergeben wurden. Nachdem jedem Parameter doppelte Anführungszeichen hinzugefügt wurden, begann er wie erwartet zu funktionieren.

Unten ist der Vor-Status meines Codes und der voll funktionsfähige Nach-Status.

Vorher - Nicht funktionierender Code

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

Nach - Funktionscode

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

Die einfachste Lösung für dieses Problem besteht darin, dass Sie \"beim Ausführen eines Shell-Skripts nur für durch Leerzeichen getrennte Argumente verwenden müssen:

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

Ihre Definition von myFunction ist falsch. Es sollte sein:

myFunction()
{
    # same as before
}

oder:

function myFunction
{
    # same as before
}

Wie auch immer, es sieht gut aus und funktioniert gut für mich unter Bash 3.2.48.

R Samuel Klatchko
quelle
5

Ich bin 9 Jahre zu spät, aber ein dynamischerer Weg wäre

function myFunction {
   for i in "$*"; do echo "$i"; done;
}
Remykarem
quelle
2
Ah gut! Das ist genau das, wonach ich bei vielen Fragen einige Zeit gesucht habe. Danke dir!
Prosoitos
2

Einfache Lösung, die für mich funktioniert hat - zitiert $ @

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

Ich konnte den tatsächlichen grep-Befehl überprüfen (dank set -x).

Bin TAN - Victor
quelle
-1

Sie könnten eine Erweiterung dieses Problems haben, wenn Ihr ursprünglicher Text in eine Variable vom Typ Zeichenfolge gesetzt wurde, zum Beispiel:

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 diesem Fall wird die Variable status_message, wenn Sie sie nicht als Zeichenfolge (umgeben von "") weiterleiten, in eine Reihe verschiedener Argumente aufgeteilt.

"$ variable" : Der aktuelle Titel ist CDE bei DEF von ABC

$ variable : Die

helmedeiros
quelle
OP verwendet myFunction "firstString" "second string with spaces" "thirdString"und es hat bei ihm nicht funktioniert. Was Sie vorschlagen, gilt also nicht für diese Frage.
DoubleDown
-2

Hatte die gleiche Art von Problem und tatsächlich war das Problem nicht die Funktion oder der Funktionsaufruf, sondern das, was ich als Argumente an die Funktion übergeben habe.

Die Funktion wurde aus dem Hauptteil des Skripts aufgerufen - dem 'main' -, also habe ich "st1 a b" "st2 c d" "st3 e f" von der Befehlszeile übergeben und sie mit myFunction $ * an die Funktion übergeben

Das $ * verursacht das Problem, da es sich zu einer Reihe von Zeichen erweitert, die beim Aufruf der Funktion unter Verwendung von Leerzeichen als Trennzeichen interpretiert werden.

Die Lösung bestand darin, den Aufruf der Funktion in der expliziten Argumentbehandlung von 'main' in Richtung der Funktion zu ändern: Der Aufruf wäre dann myFunction "$ 1" "$ 2" "$ 3", wodurch das Leerzeichen in Zeichenfolgen erhalten bleibt, da die Anführungszeichen begrenzt werden die Argumente ... Wenn ein Parameter also Leerzeichen enthalten kann, sollte er bei allen Funktionsaufrufen explizit behandelt werden.

Da dies der Grund für lange Suchen nach Problemen sein kann, ist es möglicherweise ratsam, niemals $ * zu verwenden, um Argumente zu übergeben ...

Hoffe, das hilft jemandem, eines Tages, irgendwo ... Jan.

Jan.
quelle
Die richtige Antwort ist "$@", nicht alle zitiert "$1", "$2"... Positions paramters noch $*.
Samveen