Boşluklu bir dizeyi bash işlev argümanı olarak iletme


173

Ben benim bash betiğindeki bir işleve boşluk içeren bir dize geçmek gerekiyor bir bash komut dosyası yazıyorum.

Örneğin:

#!/bin/bash

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

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

Çalıştırıldığında beklediğim çıktı:

firstString
second string with spaces
thirdString

Ancak, gerçekte çıktı:

firstString
second
string

Boşluklu bir dizeyi bash içindeki bir işleve tek bir argüman olarak iletmenin bir yolu var mı?


Benim için çalışıyor ... "işlev bla () {echo $ 1;}" olsa da işlevler için tam sözdizimi kullanıyorum, tek bir astar içine kısa bir tane yapamıyorum. Bir fark yarattığından emin değilim. Hangi bash sürümü?
Eugene

8
deneyin echo "$@"veya for i in "$@"; do echo $i ; doneboşluk içeren doğru alıntılanan parametreleri kullanarak için. Bu, bölüm bashaltındaki tüm belgelerde çok açık bir şekilde belirtilmiştir positional parameters.
Samveen

1
Ben bir parametre olarak bir alıntı dize ve parametrenin bir parçası olarak tanınan dize sadece ilk kelime geçmeye çalışırken benzer bir sorun yaşıyordu. Samveen'in $ 1 yerine $ @ değiştirme önerisi benim için çalıştı. İşlev için yalnızca bir parametre geçiriyordum, ancak for deyimini kullanarak daha fazla geçiriyor olsaydım gerekli olurdu.
Erin Geyer


1
deneyin myFunction "$@"
vimjet

Yanıtlar:


176

tırnak işaretleri koymanız gerekir ve ayrıca işlev bildiriminiz yanlıştır.

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

Diğerleri gibi benim için de işe yarıyor. Hangi kabuğu kullandığınızı bize bildirin.


3
Bu benim için de çok iyi çalışıyor. MyFunction içinde başka bir işlev çağırıyorsak, tırnak işaretleri ile argümanlar iletin. Şerefe :)
minhas23

2
Neden tekliflere ihtiyaç duyduğunu açıklayabilir misin? Hem birlikte hem de olmadan denedim ve bu benim için çalışmadı. Ubuntu 14.04, GNU bash, sürüm 4.3.11 (1) -release (x86_64-pc-linux-gnu) kullanıyorum. Ne yapar Benim için çalışmaya $ kullanıyor @ (tırnaklı veya tırnaksız).
Kyle Baker

@KyleBaker, tırnak işaretleri olmadan, $@tıpkı alıntılanmamış gibi davranır $*- sonuçlar dize bölünür ve daha sonra ayrı ayrı glob genişletilir, böylece sekmeleriniz varsa boşluklara dönüştürülür, glob ifadeleri olarak değerlendirilebilecek kelimeler varsa vb olacaktır
Charles Duffy

17

Yukarıdaki soruna başka bir çözüm, her dizeyi bir değişkene ayarlamak, işlevi bir dolar işareti ile belirtilen değişkenlerle çağırmaktır \$. Daha sonra işlevde evaldeğişkeni okumak ve çıktıyı beklendiği gibi kullanın.

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

Çıktı daha sonra:

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

Buna benzer bir sorunu çözmeye çalışırken, değişkenlerimin alanla sınırlı olduğunu düşünerek UNIX konusuna giriyordum. Daha awksonra rapor oluşturmak için kullanılan değişkenler bir dizi ayarlamak için kullanarak bir işleve bir boru ayrılmış dize geçmek çalışıyordu . Başlangıçta ghostdog74 tarafından gönderilen çözümü denedim ama tüm parametrelerim tırnak içinde geçmediği için işe yaramadı. Her parametreye çift tırnak ekledikten sonra beklendiği gibi çalışmaya başladı.

Aşağıda kodumun önceki durumu ve durumdan sonra tamamen çalışıyor.

Önce - Çalışmayan Kod

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

Sonrası - İşleyen Kod

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

Bu sorunun en basit çözümü, yalnızca \"bir kabuk betiği çalıştırırken boşlukla ayrılmış bağımsız değişkenler için kullanmanız gerektiğidir :

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

5

MyFunction tanımınız yanlış. Olmalı:

myFunction()
{
    # same as before
}

veya:

function myFunction
{
    # same as before
}

Her neyse, Bash 3.2.48'de iyi görünüyor ve benim için iyi çalışıyor.


5

9 yıl geç kaldım ama daha dinamik bir yol

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

2
Ah harika! bu tam olarak birçok soru için bir süredir aradığım şeydi. Teşekkür ederim!
prosoitos

2

Benim için çalışan basit bir çözüm - alıntı $ @

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

Gerçek grep komutunu (set -x sayesinde) doğrulayabilirim.


-1

İlk metninizin bir dize türü değişkenine ayarlanması durumunda bu sorunun bir uzantısına sahip olabilirsiniz, örneğin:

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
}

Bu durumda, status_message değişkenini dize olarak iletmezseniz ("" ile çevrelenir) farklı argümanlar kümesine bölünür.

"$ variable" : Geçerli parça DEF'de ABC tarafından CDE

$ değişkeni :


OP kullanıldı myFunction "firstString" "second string with spaces" "thirdString"ve onun için işe yaramadı. Dolayısıyla önerdiğiniz şey bu soru için geçerli değildir.
doubleDown

-2

Aynı tür bir sorun vardı ve aslında sorun fonksiyon veya fonksiyon çağrısı değil, fonksiyona argüman olarak geçtiğim şeydi.

İşlev komut dosyasının gövdesinden çağrıldı - 'main' - bu yüzden komut satırından "st1 a b" "st2 c d" "st3 e f" yi geçtim ve myFunction $ * kullanarak işleve aktardım

$ *, Boşluğun ayırıcı olarak kullanıldığı fonksiyon çağrısında yorumlanacak bir karakter kümesine genişlediğinden soruna neden olur.

Çözüm, işleve yapılan çağrıyı 'main' işlevinden işleve doğru değiştirerek değiştirmektir: çağrı daha sonra tırnak işaretleri sınırlanacak şekilde dizelerdeki boşlukları koruyacak olan myFunction "$ 1" "$ 2" "$ 3" olacaktır. bağımsız değişkenler ... Dolayısıyla, bir parametre boşluk içerebilirse, tüm işlev çağrıları sırasında açıkça işlenmelidir.

Bu, sorunlara uzun süren aramaların nedeni olabileceğinden, argümanları iletmek için asla $ * kullanmamak akıllıca olabilir ...

Umarım bu birine bir gün, bir yerde yardımcı olur ...


Doğru cevap "$@"değil tüm alıntılanan, "$1", "$2", ... pozisyonel parametresinin tanımlanması ne de $*.
Samveen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.