Melewati string dengan spasi sebagai argumen fungsi di bash

173

Saya sedang menulis skrip bash di mana saya harus meneruskan string yang berisi spasi ke fungsi di skrip bash saya.

Sebagai contoh:

#!/bin/bash

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

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

Saat dijalankan, output yang saya harapkan adalah:

firstString
second string with spaces
thirdString

Namun, sebenarnya apa yang dihasilkan adalah:

firstString
second
string

Apakah ada cara untuk melewatkan string dengan spasi sebagai argumen tunggal ke fungsi dalam bash?

Grant Limberg
sumber
Bekerja untuk saya ... Saya menggunakan sintaks penuh untuk fungsi meskipun "function bla () {echo $ 1;}", tidak dapat membuat pendek menjadi satu liner. Tidak yakin itu membuat perbedaan. Versi bash apa?
Eugene
8
coba echo "$@"atau for i in "$@"; do echo $i ; donegunakan parameter yang dikutip dengan benar yang berisi spasi. Ini adalah yang sangat jelas disebutkan dalam semua bashdokumentasi di bawah positional parametersbagian.
Samveen
1
Saya mengalami masalah yang sama, mencoba untuk melewatkan satu string yang dikutip sebagai parameter dan hanya kata pertama dari string yang diakui sebagai bagian dari parameter. Saran Samveen untuk mengubah $ 1 menjadi $ @ bekerja untuk saya. Perhatikan bahwa saya hanya meneruskan satu parameter ke fungsi, tetapi jika saya telah melewati lebih banyak menggunakan pernyataan for akan diperlukan.
Erin Geyer
1
coba myFunction "$@"
vimjet

Jawaban:

176

Anda harus memberi tanda kutip dan juga, deklarasi fungsi Anda salah.

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

Dan seperti yang lain, itu bekerja untuk saya juga. Beri tahu kami versi shell yang Anda gunakan.

ghostdog74
sumber
3
Ini bekerja sangat baik untuk saya juga. Jika kita memanggil fungsi lain di dalam myFunction maka berikan argumen dengan tanda kutip. Cheers :)
minhas23
2
Bisakah Anda jelaskan mengapa orang perlu mengutip? Saya mencoba keduanya dengan dan tanpa, dan itu tidak berhasil untuk saya. Saya menggunakan Ubuntu 14.04, GNU bash, versi 4.3.11 (1) -release (x86_64-pc-linux-gnu). Apa yang dilakukannya kerja bagi saya adalah menggunakan $ @ (dengan atau tanpa tanda kutip).
Kyle Baker
@KyleBaker, tanpa tanda kutip, $@berperilaku seperti tanda kutip $*- hasilnya adalah string-split dan kemudian secara individual diperluas, jadi jika Anda memiliki tab, mereka akan dikonversi menjadi spasi, jika Anda memiliki kata-kata yang dapat dievaluasi sebagai ekspresi glob mereka akan, dll.
Charles Duffy
17

Solusi lain untuk masalah di atas adalah mengatur setiap string ke variabel, panggil fungsi dengan variabel yang ditandai oleh tanda dolar literal \$. Kemudian dalam fungsi gunakan evaluntuk membaca variabel dan output seperti yang diharapkan.

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

Outputnya adalah:

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

Dalam mencoba memecahkan masalah yang mirip dengan ini, saya mengalami masalah UNIX berpikir variabel saya dibatasi oleh ruang. Saya mencoba untuk melewatkan string yang dibatasi pipa ke fungsi yang digunakan awkuntuk mengatur serangkaian variabel yang nantinya digunakan untuk membuat laporan. Saya awalnya mencoba solusi yang diposting oleh ghostdog74 tetapi tidak bisa berfungsi karena tidak semua parameter saya diteruskan dalam tanda kutip. Setelah menambahkan tanda kutip ganda untuk setiap parameter kemudian mulai berfungsi seperti yang diharapkan.

Di bawah ini adalah status sebelum kode saya dan berfungsi penuh setelah status.

Sebelum - Kode Tidak Berfungsi

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

Setelah - Kode Berfungsi

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

Solusi paling sederhana untuk masalah ini adalah Anda hanya perlu menggunakan \"argumen yang dipisahkan oleh ruang saat menjalankan skrip shell:

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

Definisi myFunction Anda salah. Harus:

myFunction()
{
    # same as before
}

atau:

function myFunction
{
    # same as before
}

Bagaimanapun, ini terlihat baik dan berfungsi dengan baik untuk saya di Bash 3.2.48.

R Samuel Klatchko
sumber
5

Saya terlambat 9 tahun, tetapi cara yang lebih dinamis

function myFunction {
   for i in "$*"; do echo "$i"; done;
}
remykarem
sumber
2
Ah bagus! inilah tepatnya yang saya cari selama beberapa waktu pada banyak pertanyaan. Terima kasih!
prosoitos
2

Solusi sederhana yang berhasil untuk saya - dikutip $ @

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

Saya bisa memverifikasi perintah grep yang sebenarnya (terima kasih untuk set -x).

Bin TAN - Victor
sumber
-1

Anda dapat memiliki ekstensi masalah ini jika teks awal Anda diatur ke variabel tipe string, misalnya:

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
}

Dalam hal ini, jika Anda tidak meneruskan variabel status_message ke depan sebagai string (dikelilingi oleh ""), variabel itu akan dibagi menjadi serangkaian argumen yang berbeda.

"$ variable" : Trek saat ini adalah CDE di DEF oleh ABC

$ variabel : The

helmedeiros
sumber
OP digunakan myFunction "firstString" "second string with spaces" "thirdString"dan itu tidak berhasil untuknya. Jadi apa yang Anda usulkan tidak berlaku untuk pertanyaan ini.
doubleDown
-2

Punya masalah yang sama dan sebenarnya masalahnya bukan fungsi atau fungsi panggilan, tapi apa yang saya sampaikan sebagai argumen untuk fungsi.

Fungsi dipanggil dari badan skrip - 'utama' - jadi saya melewati "st1 a b" "st2 c d" "st3 e f" dari baris perintah dan meneruskannya ke fungsi menggunakan myFunction $ *

$ * Menyebabkan masalah saat ia mengembang menjadi seperangkat karakter yang akan ditafsirkan dalam panggilan ke fungsi menggunakan spasi sebagai pembatas.

Solusinya adalah mengubah panggilan ke fungsi dalam penanganan argumen eksplisit dari 'utama' ke fungsi: panggilan itu kemudian akan menjadi myFunction "$ 1" "$ 2" "$ 3" yang akan melestarikan spasi putih di dalam string karena tanda kutip akan membatasi argumen ... Jadi jika parameter dapat berisi spasi, harus ditangani secara eksplisit di seluruh panggilan fungsi.

Karena ini mungkin menjadi alasan pencarian panjang untuk masalah, mungkin bijaksana untuk tidak menggunakan $ * untuk melewati argumen ...

Semoga ini bisa membantu seseorang, suatu hari nanti, di suatu tempat ... Jan.

Jan
sumber
Jawaban yang benar adalah "$@", tidak semua dikutip "$1", "$2", ... paramters posisi atau $*.
Samveen