Обновление массива аргументов вызывающей стороны из функции - PullRequest
2 голосов
/ 14 марта 2019

В Bash я могу установить $@ таким образом:

set -- a b c

Затем я могу проверить содержимое $@:

printf '%s\n' "$@"

, которое будет отображать:

a
b
c

Однако, если я сделаю это в функции:

f() {
    set d e f
}

set a b c
f
printf '%s\n' "$@"

Я все равно получу

a
b
c

, а не

d
e
f

Какя могу сделать так, чтобы моя функция обновления вызывающего абонента $@?Я попытался с BASH_ARGV , но это не сработало.

Я пытаюсь написать функцию, которая обрабатывает аргументы командной строки и удаляет оттуда определенные элементы (при установке переменной), такчто звонящий не должен беспокоиться о них.Например, я хочу, чтобы все мои сценарии включали ведение журнала отладки, если я вызываю их с помощью --debug без необходимости писать код для обработки этого в каждом сценарии и помещать эту логику в общую функцию "источника" вместо этого.

Примечание: я не хочу раскошелиться на скорлупу.

Ответы [ 2 ]

0 голосов
/ 14 марта 2019

Это вопрос scope: Каждая функция имеет свой собственный массив параметров независимо от сценария:

$ cat test.bash 
#!/usr/bin/env bash
f() {
    printf '%s\n' "Function arguments:" "$@"
}
printf '%s\n' "Script arguments:" "$@"
f 'a b' 'c d'
$ chmod u+x test.bash
$ ./test.bash 'foo bar' baz
Script arguments:
foo bar
baz
Function arguments:
a b
c d

Таким образом, когда вы set массив параметров, это применяется только в пределах текущей области. Если вы хотите изменить массив параметров скрипта, вам нужно set это вне любой функции. Такие хаки, как set -- $(f), вообще не будут работать, потому что они не могут обрабатывать пробелы в аргументах.

Общее решение становится намного хуже: вам нужно printf '%s\0' "$parameter" в функции и while IFS= read -r -d'' -u9 в скрипте, чтобы поместить возвращаемые значения в массив, а затем set -- "${arguments[@]}".

Я надеюсь, что это можно сделать надежно как-то иначе, но это все, что я получил.

0 голосов
/ 14 марта 2019

Вы не можете изменить значения аргументов, так как они передаются по ссылке в функциях bash.

Лучшее, что вы можете сделать, - это передать аргументы, которые вы хотите обработать, и вернуть те, которые еще не обработаны.

Что-то в строках:

process_arguments() {
    # process the arguments
    echo "original arguments : $@"
    local new_arguments=(a c)

    echo ${new_arguments[@])
}

new_arguments=$(process_arguments a b c)
set -- $new_arguments

Если вам не нужна проблема «подоболочки», вы можете использовать глобальную переменную:

arguments=""

process_arguments() {
    # process the arguments
    echo "original arguments : $@"
    local new_arguments=(a c)
    arguments="${new_arguments[@]}"
}

process_arguments a b c # no subshell
set -- $arguments        

Как подсказывает @ruakh, вы можете также использовать arguments в качестве массива, например:

arguments=()

process_arguments() {
    # process the arguments
    echo "original arguments : $@"
    local new_arguments=(a c)
    arguments=( "${new_arguments[@]}" )
}

process_arguments a b c # no subshell
set -- "${arguments[@]}"
...