Выполняется ли функция оболочки в подоболочке

Я пытаюсь обойти проблему, мне кажется, что нельзя передать открытое соединение db2 в подоболочку.

Моя кодовая организация выглядит следующим образом:

Сценарий драйвераmy_driver.sh)

# foo.sh defines baz() bar(), which use a db2 connection
# Also the "$param_file" is set in foo.sh!
source foo.sh

db2 "connect to $dbName USER $dbUser using $dbPass"

function doit
{
    cat $param_file | while read params
    do
        baz $params
        bar $params
    done
}

doit

Я упростил свой код, но приведенного выше достаточно, чтобы дать представление. Я начинаю выше:

my_driver.sh

Теперь моя настоящая проблема в том, что соединение db2 недоступно в подоболочке:

Я устал:

. my_driver.sh

Не помогает

Если я сделаю это вручную из командной строки:

source foo.sh

И выставил $params вручную:

baz $params
bar $params

Тогда это действительно работает! Таким образом, кажется, что doit или что-то еще действует так, как если бы bar и baz выполнялись из подоболочки.

Я был бы в восторге, если бы я мог каким-то образом выяснить, как передать открытое соединение db2 в подоболочку, было бы лучше всего.

В противном случае мне кажется, что эти функции оболочки выполняются в подоболочке. Есть ли способ обойти это?


person lzc    schedule 22.03.2016    source источник
comment
Думаю, ответ для вас очевиден. Да, это в подоболочке! вы можете легко проверить это, попытавшись распечатать переменные среды.   -  person raam86    schedule 22.03.2016
comment
Да, это так ... но можно запустить bar или baz нет в подоболочке?   -  person lzc    schedule 22.03.2016
comment
В вашем коде я не вижу возможности, чтобы baz или bar выполнялись в подоболочке. Наверное, они сами в подоболочке запускают команды db2?   -  person dekkard    schedule 22.03.2016
comment
Спасибо @dekkard вы заставили меня задуматься :) так что пока я все еще не уверен, действительно ли bar или baz вызываются в подоболочке, но я решил свою проблему, обернув свои db2 вызовы в { кудри }!   -  person lzc    schedule 22.03.2016
comment
Этот последний комментарий был просто неправильным, хм, как я могу просто удалить только этот комментарий?   -  person lzc    schedule 27.03.2016
comment
@lzc: если бы вы включили канал и цикл while в свой исходный вопрос, было бы намного проще ответить правильно. Редактирование действительно делает это другим вопросом, и вы должны хотя бы признать это, указав, что он был отредактирован. Вызов функции не требует подоболочки, но конвейер требует.   -  person rici    schedule 28.03.2016


Ответы (2)


Оболочка не создает подоболочку для запуска функции.

Конечно, он создает подоболочки для многих других целей, не все из которых могут быть очевидны. Например, он создает подоболочки в реализации |.

db2 требует, чтобы все команды db2 имели того же родителя, что и команда db2, которая установила соединение. Вы можете зарегистрировать PID, используя что-то вроде:

echo "Execute db2 from PID $$" >> /dev/stderr
db2 ...

(до тех пор, пока команда db2 не выполняется внутри скобок конвейера или оболочки.)


Одна из возможных проблем в показанном коде (которая имела бы совсем другой симптом) - это использование нестандартного синтаксиса.

function f

Чтобы определить функцию. Стандартная оболочка ожидает

f()

Bash понимает и то, и другое, но если у вас нет строки shebang или вы выполняете файл сценария с помощью команды sh, вы в конечном итоге используете системную оболочку по умолчанию, которой может быть не bash.

person rici    schedule 22.03.2016
comment
К вашему сведению: я использую bash, а AFAIK с использованием ключевого слова function - это необязательно также >> /dev/stderr вводит в заблуждение или по какой-то причине у меня не работает ... вы хотели сказать: echo hello world 2>> /tmp/my_stderr.log >&2? - person lzc; 27.03.2016

Нашел решение, но пока не могу полностью объяснить проблему ....

если вы измените doit следующим образом, он работает!

function doit
{
    while read params
    do
        baz $params
        bar $params
    done < $param_file
}

Только я не уверен, почему? и как я могу это доказать ...

Если я вставлю код отладки:

echo debug check with PID=$$ PPID=$PPID and SHLVL=$SHLVL

Я получаю те же результаты с | или нет. Я понимаю, что cat $param_file | while read params создает подоболочку, однако мои отладочные операторы всегда показывают один и тот же PID и PPID ...

Итак, моя проблема решена, но мне не хватает некоторых объяснений.

Мне также интересно, не будет ли этот вопрос более подходящим для сообщества unix.stackexchange?

person lzc    schedule 27.03.2016
comment
Переменная BASH_SUBSHELL в отладочном коде действительно показывает, что правая сторона | является подоболочкой ... таким образом, любые последующие вызовы db2 больше не находятся в родительской оболочке! - person lzc; 28.03.2016