Передавання рядка з пробілами як аргумент функції в bash


173

Я пишу bash-скрипт, де мені потрібно передати рядок, що містить пробіли, до функції в моєму скрипті bash.

Наприклад:

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

Чи є спосіб передавати рядок з пробілами як єдиний аргумент функції в bash?


Для мене працює ... Я використовую повний синтаксис для функцій, хоча "функція bla () {echo $ 1;}", не можу зробити короткий в один вкладиш. Не впевнений, що це має значення. Яка версія bash?
Євген

8
спробуйте echo "$@"або for i in "$@"; do echo $i ; doneдля використання правильно наведених параметрів, що містять пробіли. Це дуже чітко зазначено у всій bashдокументації в positional parametersрозділі.
Samveen

1
У мене виникли подібні проблеми, намагаючись передати один цитуваний рядок як параметр, і лише перше слово рядка було визнано частиною параметра. Пропозиція Самвена змінити $ 1 на $ @ працювала для мене. Зауважте, що я передавав у функцію лише один параметр, але якби я передав більше, використовуючи оператор for, було б необхідно.
Ерін Гейєр


1
спробуйте myFunction "$@"
vimjet

Відповіді:


176

Ви повинні поставити лапки, а також, ваша декларація функції неправильна.

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

І як і інші, це працює і для мене. Розкажіть, яку версію оболонки ви використовуєте.


3
Це дуже добре працює і для мене. Якщо ми викликаємо іншу функцію всередині myFunction, то передаємо аргументи з цитатами. Ура :)
minhas23

2
Чи можете ви пояснити, чому потрібні цитати? Я пробував і з, і без, і мені це не вийшло. Я використовую Ubuntu 14.04, GNU bash, версія 4.3.11 (1) -release (x86_64-pc-linux-gnu). Що робить роботу для мене з допомогою $ @ (з або без лапок).
Кайл Бейкер

@KyleBaker без лапок $@поводиться так само, як без котирування $*- результати розбиваються на рядки, а потім окремо розширюються на глобальний, так що якщо у вас є вкладки, вони будуть перетворені на пробіли, якщо у вас є слова, які можна оцінити як вирази глобальних буде і т. д.
Чарльз Даффі

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 неправильне. Вона повинна бути:

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 вперед як рядок (оточений ""), вона буде розділена на макет різних аргументів.

"змінна $" : поточний трек є CDE на DEF від ABC

$ змінна :


ОП використовував, myFunction "firstString" "second string with spaces" "thirdString"і це не працювало для нього. Тож те, що ви пропонуєте, не стосується цього питання.
подвійнеDown

-2

Була однакова проблема і насправді проблема полягала не в функції або виклику функції, а в тому, що я передав як аргументи функції.

Функція викликалася з корпусу скрипту - "головний" - тому я передав "st1 a b" "st2 c d" "st3 e f" з командного рядка і передав її у функцію за допомогою myFunction $ *

$ * Викликає проблему, оскільки вона розширюється на набір символів, які будуть інтерпретовані у виклику до функції, використовуючи пробіл як роздільник.

Рішення полягало в тому, щоб змінити виклик функції в явній обробці аргументів з 'головного' на функцію: тоді виклик буде myFunction "$ 1" "$ 2" "$ 3", що збереже пробіл всередині рядків, оскільки лапки будуть обмежені аргументи ... Отже, якщо параметр може містити пробіли, він повинен оброблятися явно протягом усіх викликів функцій.

Оскільки це може бути причиною тривалих пошуків проблем, може бути розумним ніколи не використовувати $ * для передачі аргументів ...

Сподіваюся, що це комусь допоможе, колись, десь… січня.


Правильна відповідь "$@", не всі лапки "$1", "$2"... позиційний paramters ні $*.
Samveen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.