Я хотел бы вернуть строку из функции Bash.
Я напишу пример в Java, чтобы показать, что я хотел бы сделать:
public String getSomeString() {
return "tadaa";
}
String variable = getSomeString();
Пример ниже работает в bash, но есть ли лучший способ сделать это?
function getSomeString {
echo "tadaa"
}
VARIABLE=$(getSomeString)
string
bash
function
return-value
Томас Ф
источник
источник
function funcName {
унаследованный до POSIX синтаксис унаследован от раннего ksh (где у него были семантические различия, которые bash не соблюдает).funcName() {
, с нетfunction
, следует использовать вместо; см. wiki.bash-hackers.org/scripting/obsoletefunction myFunction { blah; }
хорошо; этоfunction myFunction() { blah }
не хорошо, то есть использование скобок с функцией ключевого слова.Ответы:
Нет лучшего способа, о котором я знаю. Bash знает только коды состояния (целые числа) и строки, записанные в стандартный вывод.
источник
somefunction && echo 'success'
). Если вы думаете о функции как о другой команде, это имеет смысл; команды не «возвращают» ничего при выходе, кроме кода состояния, но они могут выводить данные в то же время, что вы можете захватить.Вы можете сделать так, чтобы функция взяла переменную в качестве первого аргумента и изменила переменную строкой, которую вы хотите вернуть.
Печать "Foo Bar Rab Oof".
Редактировать : добавлено цитирование в соответствующем месте, чтобы разрешить пробел в строке для комментария @Luca Borrione.
Изменить : в качестве демонстрации, см. Следующую программу. Это решение общего назначения: оно даже позволяет вам получить строку в локальную переменную.
Это печатает:
Edit : показать , что значение исходного переменной является доступны в функции, как это было неправильно раскритикован @Xichen Ли в комментарии.
Это дает вывод:
источник
fgm
ответ, написанный в упрощенном виде? Это не будет работать, если строкаfoo
содержит пробелы, в то время как строкаfgm
будет ... как он показывает.\$$1
. Если вы ищете что-то другое, пожалуйста, дайте мне знать.printf '%q' "$var"
. % q это строка формата для экранирования оболочки. Тогда просто передайте это сырым.Все ответы выше игнорируют то, что было сказано на странице руководства bash.
Пример кода
И вывод
Также в pdksh и ksh этот скрипт делает то же самое!
источник
Bash, начиная с версии 4.3, февраль 2014 (?), Имеет явную поддержку ссылочных переменных или ссылок на имена (namerefs), помимо «eval», с той же выгодной эффективностью и эффектом косвенности, которые могут быть более понятными в ваших сценариях, а также сложнее «забыть« eval »и исправить эту ошибку»:
а также:
Например ( РЕДАКТИРОВАТЬ 2 : (спасибо, Рон), пространство имен (с префиксом) имени внутренней переменной функции, чтобы минимизировать конфликты внешних переменных, которые должны окончательно ответить правильно, проблема, поднятая в комментариях Карстена):
и тестирование этого примера:
Обратите внимание, что встроенная команда bash «Declare», когда используется в функции, делает объявленную переменную «локальной» по умолчанию, и «-n» также может использоваться с «локальной».
Я предпочитаю отличать переменные «важное объявление» от «скучных локальных» переменных, поэтому использование «объявления» и «локального» таким образом действует как документация.
РЕДАКТИРОВАТЬ 1 - (Ответ на комментарий ниже от Karsten) - я не могу больше добавлять комментарии ниже, но комментарий Karsten заставил меня задуматься, поэтому я сделал следующий тест, который РАБОТАЕТ КАЧЕСТВЕННО, AFAICT - Karsten, если вы читаете это, пожалуйста, предоставьте точный набор шагов теста из командной строки, показывающих, что проблема, по вашему мнению, существует, потому что эти следующие шаги работают просто отлично:
(Я запустил это только сейчас, после вставки вышеупомянутой функции в термин bash - как видите, результат работает просто отлично.)
источник
declare
внутри функций создаются локальные переменные (эта информация не передаетсяhelp declare
): "... При использовании в функции объявление и набор текста делают каждое имя локальным, как с локальной командой, если только - g опция предоставлена ... "K=$1; V=$2; eval "$A='$V'";
, но одну ошибку (например, пустой или пропущенный параметр), и это будет более опасно. @zenaan Проблема, поднятая @Karsten, применяется, если вы выбрали «message» в качестве имени возвращаемой переменной вместо «ret».Как bstpierre выше, я использую и рекомендую использовать явное именование выходных переменных:
Обратите внимание на использование цитирования $. Это позволит избежать интерпретации содержимого
$result
как специальных символов оболочки. Я обнаружил, что это на порядок быстрее, чемresult=$(some_func "arg1")
выражение захвата эха. Разница в скорости кажется еще более заметной при использовании bash на MSYS, где захват stdout из вызовов функций почти катастрофичен.Можно отправлять локальные переменные, поскольку в bash динамически ограничиваются локальные переменные:
источник
echo
внутренней части функции в сочетании с подстановкой команд!Вы также можете захватить вывод функции:
Выглядит странно, но лучше, чем использование глобальных переменных ИМХО. Передача параметров работает как обычно, просто поместите их в фигурные скобки или кавычки.
источник
Самое простое и надежное решение - использовать подстановку команд, как писали другие люди:
Недостатком является производительность, так как для этого требуется отдельный процесс.
Другой метод, предложенный в этом разделе, а именно, передача имени переменной для присвоения в качестве аргумента, имеет побочные эффекты, и я бы не рекомендовал его в его базовой форме. Проблема в том, что вам, вероятно, понадобятся некоторые переменные в функции для вычисления возвращаемого значения, и может случиться так, что имя переменной, предназначенной для хранения возвращаемого значения, будет мешать одной из них:
Конечно, вы можете не объявлять внутренние переменные функции как локальные, но вы действительно должны всегда делать это, так как в противном случае вы можете, случайно, перезаписать несвязанную переменную из родительской области, если есть переменная с таким же именем ,
Одним из возможных обходных путей является явное объявление переданной переменной как глобальной:
Если в качестве аргумента передано имя «x», вторая строка тела функции перезапишет предыдущее локальное объявление. Но сами имена могут по-прежнему мешать, поэтому, если вы намерены использовать значение, ранее сохраненное в переданной переменной, до записи туда возвращаемого значения, имейте в виду, что вы должны скопировать его в другую локальную переменную в самом начале; в противном случае результат будет непредсказуемым! Кроме того, это будет работать только в самой последней версии BASH, а именно 4.2. Более переносимый код может использовать явные условные конструкции с тем же эффектом:
Возможно, самое элегантное решение - просто зарезервировать одно глобальное имя для возвращаемых значений функции и последовательно использовать его в каждой написанной вами функции.
источник
eval
и дляdeclare -n
решений. Обходной путь использования единственного выделенного имени переменной, какresult
для всех выходных параметров, кажется единственным решением, которому не требуется, чтобы функции знали всех своих вызывающих, чтобы избежать конфликтов.Как упоминалось ранее, «правильный» способ вернуть строку из функции - это подстановка команд. В случае, если функции также необходимо вывести на консоль (как упоминалось в @Mani выше), создайте временный fd в начале функции и перенаправьте на консоль. Закройте временный fd перед возвратом вашей строки.
выполнение скрипта без параметров выдает ...
надеюсь, это поможет людям
-Энди
источник
3>&1
в начале скрипта, затем манипулируя&1
&3
и другим заполнителем&4
внутри функции. Хотя уродливо все вокруг.Вы можете использовать глобальную переменную:
Это дает
источник
Чтобы проиллюстрировать мой комментарий к ответу Энди, с дополнительными манипуляциями с дескриптором файла, чтобы избежать использования
/dev/tty
:Тем не менее, все еще противный.
источник
То, как вы это делаете, - единственный способ сделать это, не выходя за рамки. Bash не имеет концепции типов возврата, только коды выхода и файловые дескрипторы (stdin / out / err и т. Д.)
источник
Обращаясь к голове Вики Роннен , учитывая следующий код:
дам
Возможно, нормальным сценарием является использование синтаксиса, используемого в
test_inside_a_func
функции, таким образом, вы можете использовать оба метода в большинстве случаев, хотя захват результатов - более безопасный метод, всегда работающий в любой ситуации, имитирующий возвращаемое значение из функции, которую вы можете найти на других языках, какVicky Ronnen
правильно указано.источник
Варианты уже все перечислены, я думаю. Выбор одного может сводиться к вопросу о наилучшем стиле для вашего конкретного приложения, и в этом смысле я хочу предложить один конкретный стиль, который я нашел полезным. В bash переменные и функции не находятся в одном и том же пространстве имен. Таким образом, обработка переменной с тем же именем, что и значение функции, является соглашением, которое, как я считаю, сводит к минимуму конфликты имен и повышает удобочитаемость, если я применяю это строго. Пример из реальной жизни:
И пример использования таких функций:
Как видите, вы можете использовать возвращаемый статус, когда вам это нужно, или игнорировать, если это не так. «Возвращенная» переменная может также использоваться или игнорироваться, но, конечно, только после вызова функции.
Конечно, это всего лишь соглашение. Вы можете не устанавливать соответствующее значение перед возвратом (отсюда мое соглашение всегда обнулять его в начале функции) или растоптать его значение, вызывая функцию снова (возможно, косвенно). Тем не менее, это соглашение, которое я считаю очень полезным, если я использую функции bash.
В противоположность ощущению, что это признак, например, «переход на perl», моя философия заключается в том, что условные обозначения всегда важны для управления сложностью любого языка.
источник
Вы можете
echo
использовать строку, но поймать ее, отправив|
функцию ( ) к чему-то другому.Вы можете сделать это
expr
, хотя ShellCheck сообщает об этом как об устаревшем.источник
myfunc | read OUTPUT ; echo $OUTPUT
ничего не дает.myfunc | ( read OUTPUT; echo $OUTPUT )
действительно получает ожидаемое значение и разъясняет, что происходит с правой стороны. Но, конечно, выход не доступен там, где вам это нужно ...Они являются ключевой проблемой любой схемы «именованных выходных переменных», в которой вызывающая сторона может передать имя переменной (с использованием
eval
илиdeclare -n
) непреднамеренного псевдонима, т. Е. Столкновения имен: с точки зрения инкапсуляции ужасно не иметь возможности добавлять или переименовывать локальная переменная в функции без предварительной проверки ВСЕХ вызывающих функций, чтобы убедиться, что они не хотят передавать то же имя, что и выходной параметр. (Или в другом направлении, я не хочу читать источник вызываемой функции, просто чтобы убедиться, что выходной параметр, который я собираюсь использовать, не является локальным в этой функции.)Единственный способ обойти это - использовать одну выделенную выходную переменную, такую как
REPLY
(как предложено Evi1M4chine ) или соглашение, подобное предложенному Роном Бурком .Однако можно иметь функции, использующие фиксированную выходную переменную внутри , а затем добавить немного сахара сверху, чтобы скрыть этот факт от вызывающей стороны , как я сделал с
call
функцией в следующем примере. Считайте это доказательством концепции, но ключевые моментыREPLY
, а также может возвращать код выхода, как обычноREPLY
(см.wrapper
Пример). Выход код функции передается через, поэтому их использование в например,if
илиwhile
или аналогичные конструкты работы , как и ожидалось.Причина, по которой это работает, заключается в том, что сама
call
функция не имеет локальных переменных и не использует никаких других переменных, за исключением тогоREPLY
, что исключает возможность конфликта имен. В тот момент, когда назначается имя выходной переменной, определяемой вызывающим, мы фактически находимся в области действия вызывающего (технически в идентичной области действияcall
функции), а не в области вызываемой функции.Вывод:
источник
шаблон bash для возврата объектов значений скаляров и массивов :
определение
вызов
источник
В моих программах, по соглашению, это то
$REPLY
,read
для чего предназначена существующая переменная, которая используется именно для этой цели.Это
echo
есНо чтобы избежать конфликтов, подойдет любая другая глобальная переменная.
Если этого недостаточно, я рекомендую решение Markarian451 .
источник
источник