Экспорт функции с определением вложенной функции и heredo c in bash - PullRequest
2 голосов
/ 06 марта 2020

Я хочу передать сегмент скрипта в подоболочку, поэтому я экспортирую его как функцию. Когда я пытался это сделать, я заметил, что не могу экспортировать функцию, содержащую вложенную функцию, которая заканчивается на heredo c.

Например:

#!/bin/bash

f() {
    g() {
        cat <<EOF
EOF
    }

    g
}

export -f f
bash -c ':'

Если я ее запусту, не работает оболочка и печатает:

bash: f: line 8: syntax error: unexpected end of file
bash: error importing function definition for `f'

Что не так с моим скриптом?

1 Ответ

2 голосов
/ 06 марта 2020

Чтобы получить экспортированные функции в подоболочки Bash сериализует их как строки и сохраняет их в простых name=value переменных окружения. Подоболочка распознает переменные среды как содержащие функции и анализирует их как таковые. Предполагается, что это невидимый механизм, но он достаточно сложен, поэтому иногда возникают ошибки ( Shellshock ).

В Bash 5.0, bash -c env показывает, что функция сериализуется в переменную окружения как:

BASH_FUNC_f%%=() {  function g () 
 { 
 cat <<EOF
 }
EOF

 g
}

Обратите внимание на размещение <<EOF. Наличие фигурной скобки внутри heredo c неверно и является источником синтаксической ошибки.

Кажется, что это регрессия в Bash 5.0. В Bash 4.4 и 4.2 он сериализован так, что работает без проблем:

BASH_FUNC_f()=() {  function g () 
 { 
 cat
 }  <<EOF
EOF

 g
}

Я не вижу соответствующих сообщений об ошибках в https://savannah.gnu.org/support/?group=bash или https://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=bash;dist=unstable. Возможно, вы могли бы отправить один?

Другие наблюдения:

  • declare -fp имеет ту же синтаксическую ошибку. Ошибка, вероятно, происходит там, а не в коде экспорта переменных среды.

    $ declare -pf f
    f () 
    { 
        function g () 
        { 
            cat <<EOF
        }
    EOF
    
        g
    }
    
  • Я не вижу способа упростить ваш тестовый пример. Отлично!

    Удаление вызова g исправляет ошибку:

    f () 
    { 
        function g () 
        { 
            cat <<EOF
    EOF
    
        }
    }
    

    Так же, как и изменение вложенного объявления в простой блок фигурных скобок:

    f () 
    { 
        { 
            cat <<EOF
    EOF
    
        }
        g
    }
    
...