Truyền một chuỗi có khoảng trắng làm đối số hàm trong bash


173

Tôi đang viết một tập lệnh bash trong đó tôi cần truyền một chuỗi chứa khoảng trắng cho một hàm trong tập lệnh bash của tôi.

Ví dụ:

#!/bin/bash

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

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

Khi chạy, đầu ra tôi mong đợi là:

firstString
second string with spaces
thirdString

Tuy nhiên, những gì thực sự đầu ra là:

firstString
second
string

Có cách nào để truyền một chuỗi có khoảng trắng dưới dạng một đối số cho hàm trong bash không?


Hoạt động với tôi ... Tôi sử dụng cú pháp đầy đủ cho các hàm mặc dù "function bla () {echo $ 1;}", không thể biến một đoạn ngắn thành một lớp lót. Không chắc chắn nó làm cho một sự khác biệt. Phiên bản nào của bash?
Eugene

8
thử echo "$@"hoặc for i in "$@"; do echo $i ; donesử dụng các tham số được trích dẫn chính xác có chứa khoảng trắng. Đây là đề cập rất rõ ràng trong tất cả các bashtài liệu dưới positional parametersphần.
Samveen

1
Tôi đã gặp một vấn đề tương tự, cố gắng truyền một chuỗi được trích dẫn làm tham số và chỉ từ đầu tiên của chuỗi được nhận dạng là một phần của tham số. Đề nghị của Samveen để thay đổi $ 1 thành $ @ làm việc cho tôi. Lưu ý rằng tôi chỉ truyền một tham số cho hàm, nhưng nếu tôi chuyển nhiều hơn bằng cách sử dụng câu lệnh for sẽ là cần thiết.
Erin Geyer


1
thử myFunction "$@"
vimjet

Câu trả lời:


176

bạn nên đặt dấu ngoặc kép và đồng thời, khai báo hàm của bạn là sai.

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

Và giống như những người khác, nó cũng làm việc cho tôi. Hãy cho chúng tôi biết phiên bản vỏ bạn đang sử dụng.


3
Điều này cũng làm việc rất tốt cho tôi. Nếu chúng ta đang gọi một hàm khác trong myFactor thì hãy chuyển các đối số bằng dấu ngoặc kép. Chúc mừng :)
minhas23

2
Bạn có thể giải thích tại sao một người cần báo giá? Tôi đã thử cả có và không, và nó không hiệu quả với tôi. Tôi đang sử dụng Ubuntu 14.04, GNU bash, phiên bản 4.3.11 (1) -release (x86_64-pc-linux-gnu). Điều gì làm việc cho tôi là sử dụng $ @ (có hoặc không có dấu ngoặc kép).
Kyle Baker

@KyleBaker, không có dấu ngoặc kép, $@hoạt động giống như không được trích dẫn $*- kết quả được phân tách chuỗi và sau đó được mở rộng toàn cầu, vì vậy nếu bạn có các tab, chúng sẽ được chuyển đổi thành khoảng trắng, nếu bạn có các từ có thể được đánh giá là biểu thức toàn cầu sẽ, v.v.
Charles Duffy

17

Một giải pháp khác cho vấn đề trên là đặt từng chuỗi thành một biến, gọi hàm với các biến được biểu thị bằng ký hiệu đô la bằng chữ \$. Sau đó, trong hàm sử dụng evalđể đọc biến và đầu ra như mong đợi.

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

Đầu ra là:

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

Khi cố gắng giải quyết một vấn đề tương tự như vậy, tôi đã gặp phải vấn đề về UNIX khi nghĩ rằng các biến của tôi bị phân định không gian. Tôi đã cố gắng truyền một chuỗi giới hạn đường ống đến một hàm bằng cách sử dụngawk một loạt các biến sau này được sử dụng để tạo báo cáo. Ban đầu tôi đã thử giải pháp được đăng bởi ghostdog74 nhưng không thể làm cho nó hoạt động được vì không phải tất cả các tham số của tôi đều được thông qua trong dấu ngoặc kép. Sau khi thêm dấu ngoặc kép vào từng tham số, nó sẽ bắt đầu hoạt động như mong đợi.

Dưới đây là trạng thái trước mã của tôi và hoạt động đầy đủ sau trạng thái.

Trước - Mã không hoạt động

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

Sau - Mã chức năng

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

Giải pháp đơn giản nhất cho vấn đề này là bạn chỉ cần sử dụng \"cho các đối số được phân tách bằng dấu cách khi chạy tập lệnh shell:

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

5

Định nghĩa của tôi về chức năng của tôi là sai. Nó nên là:

myFunction()
{
    # same as before
}

hoặc là:

function myFunction
{
    # same as before
}

Dù sao, nó có vẻ tốt và hoạt động tốt với tôi trên Bash 3.2.48.


5

Tôi trễ 9 năm nhưng một cách năng động hơn sẽ là

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

2
Tuyệt quá! đây chính xác là những gì tôi đã tìm kiếm một thời gian cho nhiều câu hỏi. Cảm ơn bạn!
prosoitos

2

Giải pháp đơn giản phù hợp với tôi - trích dẫn $ @

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

Tôi có thể xác minh lệnh grep thực tế (nhờ tập -x).


-1

Bạn có thể có phần mở rộng của vấn đề này trong trường hợp văn bản ban đầu của bạn được đặt thành biến loại chuỗi, ví dụ:

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
}

Trong trường hợp này, nếu bạn không chuyển biến status_message về phía trước dưới dạng chuỗi (được bao quanh bởi ""), nó sẽ được chia thành một nhóm các đối số khác nhau.

"$ biến" : Bản nhạc hiện tại là CDE tại DEF của ABC

$ biến :


OP đã sử dụng myFunction "firstString" "second string with spaces" "thirdString"và nó không làm việc cho anh ta. Vì vậy, những gì bạn đề xuất không áp dụng cho câu hỏi này.
doubleDown

-2

Có cùng một loại vấn đề và trên thực tế, vấn đề không phải là chức năng cũng không phải là chức năng gọi, mà là những gì tôi chuyển qua làm đối số cho hàm.

Hàm được gọi từ phần thân của tập lệnh - 'chính' - vì vậy tôi đã chuyển "st1 a b" "st2 c d" "st3 e f" từ dòng lệnh và chuyển nó cho hàm bằng myFactor $ *

$ * Gây ra vấn đề khi nó mở rộng thành một tập hợp các ký tự sẽ được diễn giải trong lệnh gọi hàm sử dụng khoảng trắng làm dấu phân cách.

Giải pháp là thay đổi cuộc gọi thành hàm trong xử lý đối số rõ ràng từ 'chính' sang hàm: cuộc gọi sau đó sẽ là myFactor "$ 1" "$ 2" "$ 3" sẽ duy trì khoảng trắng bên trong chuỗi vì dấu ngoặc kép sẽ phân định các đối số ... Vì vậy, nếu một tham số có thể chứa khoảng trắng, thì nó sẽ được xử lý rõ ràng trong tất cả các lệnh gọi của hàm.

Vì đây có thể là lý do cho các tìm kiếm dài cho các vấn đề, nên có thể không bao giờ sử dụng $ * để truyền các đối số ...

Hy vọng điều này sẽ giúp ai đó, một ngày nào đó, ở đâu đó ... Jan.


Câu trả lời đúng là "$@", không phải tất cả trích dẫn "$1", "$2"... paramters vị trí cũng không $*.
Samveen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.