Передача строки с пробелами в качестве аргумента функции в 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?


Работает для меня ... Я использую полный синтаксис для функций, хотя "function bla () {echo $ 1;}", не могу превратить один в одну строку. Не уверен, что это имеет значение. Какая версия bash?
Евгений

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

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) -релиз (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
Ах, здорово! это именно то, что я искал некоторое время по многим вопросам. Спасибо!
Просоитос

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

переменная $ :


ОП использовал, myFunction "firstString" "second string with spaces" "thirdString"и у него это не сработало. То, что вы предлагаете, не относится к этому вопросу.
Двойной Даун

-2

Была такая же проблема, и на самом деле проблема была не в функции и не в вызове функции, а в том, что я передал в качестве аргументов функции.

Функция была вызвана из тела скрипта - 'main' - поэтому я передал "st1 a b" "st2 c d" "st3 e f" из командной строки и передал ее функции, используя myFunction $ *

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

Решение состояло в том, чтобы изменить вызов функции при явной обработке аргументов с «основного» на функцию: тогда вызовом будет myFunction «$ 1» «$ 2» «$ 3», который сохранит пробел внутри строк, поскольку кавычки будут разделять аргументы ... Таким образом, если параметр может содержать пробелы, он должен обрабатываться явно во всех вызовах функций.

Поскольку это может быть причиной долгих поисков проблем, может быть разумно никогда не использовать $ * для передачи аргументов ...

Надеюсь, это поможет кому-нибудь, когда-нибудь, где-то ... Январь


Правильный ответ "$@", не все кавычки "$1", "$2"... позиционный paramters ни $*.
Самвин
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.