ผ่านสตริงที่มีช่องว่างเป็นอาร์กิวเมนต์ฟังก์ชั่นในทุบตี


173

ฉันกำลังเขียนสคริปต์ทุบตีที่ฉันต้องการส่งสตริงที่มีช่องว่างไปยังฟังก์ชันในสคริปต์ทุบตีของฉัน

ตัวอย่างเช่น:

#!/bin/bash

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

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

เมื่อเรียกใช้ผลลัพธ์ที่ฉันต้องการคือ:

firstString
second string with spaces
thirdString

อย่างไรก็ตามสิ่งที่เอาท์พุทคือ:

firstString
second
string

มีวิธีการส่งผ่านสตริงที่มีช่องว่างเป็นอาร์กิวเมนต์เดียวกับฟังก์ชั่นในทุบตี?


ใช้งานได้สำหรับฉัน ... ฉันใช้ซินแทกซ์แบบเต็มสำหรับฟังก์ชั่นแม้ว่า "function bla () {echo $ 1;}" "ไม่สามารถทำการย่อให้เป็นหนึ่งบรรทัดได้ ไม่แน่ใจว่ามันสร้างความแตกต่าง ทุบตีรุ่นใด
ยูจีน

8
ลองecho "$@"หรือfor i in "$@"; do echo $i ; doneใช้พารามิเตอร์ที่ยกมาอย่างถูกต้องที่มีช่องว่าง นี่คือที่กล่าวถึงอย่างชัดเจนในbashเอกสารทั้งหมดภายใต้positional parametersส่วน
Samveen

1
ฉันมีปัญหาที่คล้ายกันพยายามส่งสตริงหนึ่งที่ยกมาเป็นพารามิเตอร์และมีเพียงคำแรกของสตริงที่ได้รับการยอมรับเป็นส่วนหนึ่งของพารามิเตอร์ ข้อเสนอแนะของ Samveen เพื่อเปลี่ยน $ 1 เป็น $ @ ได้ผลสำหรับฉัน โปรดทราบว่าฉันส่งพารามิเตอร์เพียงหนึ่งพารามิเตอร์ไปยังฟังก์ชัน แต่ถ้าฉันส่งผ่านการใช้คำสั่ง for ให้มากขึ้นก็จำเป็น
Erin Geyer


1
ลอง myFunction "$@"
vimjet

คำตอบ:


176

คุณควรใส่เครื่องหมายคำพูดและการประกาศฟังก์ชั่นของคุณผิด

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

และก็เหมือนกับคนอื่น ๆ มันก็ใช้ได้ผลสำหรับฉันเช่นกัน บอกเราว่าคุณใช้เชลล์รุ่นใด


3
มันใช้งานได้ดีมากสำหรับฉันด้วย หากเรากำลังเรียกใช้ฟังก์ชันอื่นภายใน myFunction ให้ส่งอาร์กิวเมนต์ที่มีเครื่องหมายคำพูด ไชโย :)
minhas23

2
คุณช่วยอธิบายได้ไหมว่าทำไมต้องมีคำพูด ฉันลองทั้งที่มีและไม่มีและมันไม่ได้ผลสำหรับฉัน ฉันใช้ Ubuntu 14.04, GNU ทุบตี, รุ่น 4.3.11 (1) - ปล่อย (x86_64-pc-linux-gnu) อะไรที่ใช้งานได้สำหรับฉันใช้ $ @ (ไม่ว่าจะมีหรือไม่มีเครื่องหมายอัญประกาศ)
Kyle Baker

@ KyleBaker โดยไม่มีเครื่องหมายอัญประกาศ$@จะทำงานเหมือนไม่มีการอ้างอิง$*- ผลลัพธ์คือการแยกสตริงและแต่ละส่วนขยายตัวดังนั้นถ้าคุณมีแท็บพวกเขาจะถูกแปลงเป็นช่องว่างถ้าคุณมีคำที่สามารถประเมินได้ว่าเป็นนิพจน์ทางสังคม จะเป็น ฯลฯ
Charles Duffy

17

\$วิธีการแก้ปัญหาดังกล่าวก็คือการตั้งค่าแต่ละสายให้กับตัวแปรเรียกใช้ฟังก์ชันที่มีตัวแปรแทนด้วยเครื่องหมายดอลลาร์อักษร จากนั้นในฟังก์ชั่นใช้evalในการอ่านตัวแปรและเอาท์พุทตามที่คาดไว้

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

ผลลัพธ์คือ:

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

ในการพยายามแก้ปัญหาที่คล้ายกันนี้ฉันพบปัญหาเกี่ยวกับ UNIX โดยที่ตัวแปรของฉันถูกลบพื้นที่ ฉันพยายามส่งสตริงที่คั่นด้วยไพพ์ไปยังฟังก์ชันที่ใช้awkเพื่อตั้งค่าชุดของตัวแปรที่ใช้ในการสร้างรายงานในภายหลัง ฉันเริ่มลองวิธีแก้ปัญหาที่โพสต์โดย ghostdog74 แต่ไม่สามารถทำงานได้เนื่องจากพารามิเตอร์ทั้งหมดของฉันไม่ได้ถูกส่งผ่านในเครื่องหมายคำพูด หลังจากเพิ่มเครื่องหมายคำพูดคู่ให้กับพารามิเตอร์แต่ละตัวมันจะเริ่มทำงานตามที่คาดไว้

ด้านล่างนี้เป็นสถานะก่อนหน้าของรหัสของฉันและทำงานอย่างเต็มที่หลังจากสถานะ

ก่อน - รหัสไม่ทำงาน

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

รหัสฟังก์ชั่นหลังจาก

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

ทางออกที่ง่ายที่สุดสำหรับปัญหานี้คือคุณต้องใช้\"สำหรับอาร์กิวเมนต์ที่คั่นด้วยช่องว่างเมื่อเรียกใช้เชลล์สคริปต์:

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

5

คำจำกัดความของฟังก์ชั่นของฉันผิด มันควรจะเป็น:

myFunction()
{
    # same as before
}

หรือ:

function myFunction
{
    # same as before
}

อย่างไรก็ตามมันดูดีและใช้งานได้ดีสำหรับฉันใน Bash 3.2.48


5

ฉันล่าช้า 9 ปีแล้ว แต่จะมีวิธีที่มีพลวัตมากขึ้น

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

2
เยี่ยมมาก! ตรงนี้เป็นสิ่งที่ฉันค้นหาในบางคำถาม ขอบคุณ!
prosoitos

2

ทางออกที่ง่ายสำหรับฉัน - เสนอราคา $ @

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

ฉันสามารถตรวจสอบคำสั่ง grep จริง (ขอบคุณ set -x)


-1

คุณสามารถมีส่วนขยายของปัญหานี้ในกรณีที่ข้อความเริ่มต้นของคุณถูกกำหนดเป็นตัวแปรชนิดสตริงตัวอย่างเช่น:

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
}

ในกรณีนี้หากคุณไม่ส่งต่อตัวแปร status_message ไปข้างหน้าเป็นสตริง (ล้อมรอบด้วย "") มันจะถูกแบ่งในการเมาท์ของอาร์กิวเมนต์ที่แตกต่างกัน

"$ variable" : แทร็กปัจจุบันคือ CDE ที่ DEF โดย ABC

$ ตัวแปร :


OP ใช้myFunction "firstString" "second string with spaces" "thirdString"แล้วและมันก็ไม่ได้ผลสำหรับเขา ดังนั้นสิ่งที่คุณเสนอจะไม่มีผลกับคำถามนี้
doubleDown

-2

มีปัญหาแบบเดียวกันและในความเป็นจริงแล้วปัญหาไม่ใช่หน้าที่หรือการเรียกใช้ฟังก์ชัน แต่สิ่งที่ฉันส่งเป็นอาร์กิวเมนต์ไปยังฟังก์ชัน

ฟังก์ชั่นถูกเรียกใช้จากเนื้อความของสคริปต์ - 'main' - ดังนั้นฉันเลยผ่าน "st1 a b" "st2 c d" "st3 e f" จากบรรทัดคำสั่งและส่งผ่านไปยังฟังก์ชันโดยใช้ myFunction $ *

$ * ทำให้เกิดปัญหาตามที่ขยายออกเป็นชุดของอักขระซึ่งจะถูกตีความในการเรียกใช้ฟังก์ชันโดยใช้ช่องว่างเป็นตัวคั่น

วิธีแก้ไขคือเปลี่ยนการเรียกใช้ฟังก์ชันในการจัดการอาร์กิวเมนต์ที่ชัดเจนจาก 'main' ไปยังฟังก์ชัน: การเรียกใช้จะเป็น myFunction "$ 1" "$ 2" "$ 3" ซึ่งจะรักษาช่องว่างภายในสตริงเนื่องจากเครื่องหมายคำพูดจะกำหนดขอบเขต อาร์กิวเมนต์ ... ดังนั้นหากพารามิเตอร์สามารถมีช่องว่างควรจัดการอย่างชัดเจนตลอดการเรียกใช้ฟังก์ชันทั้งหมด

เนื่องจากนี่อาจเป็นเหตุผลสำหรับการค้นหาปัญหาที่ยาวนานคุณอาจไม่ควรใช้ $ * เพื่อผ่านการโต้แย้ง ...

หวังว่านี่จะช่วยใครซักคนสักวันหนึ่ง ... ม.ค.


คำตอบที่ถูกต้องคือ"$@"ไม่ได้ทั้งหมดที่ยกมา"$1", "$2"... $*พารามิเตอร์ตำแหน่งมิได้
Samveen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.