source / dev / stdin não funciona como esperado

4

Vamos começar com testes simples que funcionam para eu verificar se source /dev/stdin pode ser usado.

# echo -ne 'echo a\necho b\n' | source /dev/stdin
a
b

Agora eu gostaria de obter uma função real.

# echo -ne 'f() { echo a; }\n' | source /dev/stdin
# f
-bash: f: command not found

Agora vamos tentar com um arquivo temporário.

# echo -ne 'f() { echo a; }\n' > tempf
# source tempf
# f
a

Então o arquivo temporário funciona. Mas é muito incerto no meu caso e não vejo nenhum motivo válido pelo qual o pipe não funcione tão bem.

# bash --version
GNU bash, version 4.2.53(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Para completar, o caso de uso real é selecionar cuidadosamente quais partes de um arquivo serão incluídas, a fim de contornar uma limitação na portabilidade do Gentoo.

post_src_unpack() {
    if type epatch_user > /dev/null 2>&1; then
        epatch_user || die
    else
        awk \
            '/^# @FUNCTION: / { p = 0 } /^# @FUNCTION: epatch(_user)?$/ { p = 1; } p { print  }' \
            /usr/portage/eclass/eutils.eclass | source /dev/stdin || die
        epatch_user || die
        unset epatch
        unset epatch_user
    fi
}

A finalidade do código é extrair apenas duas funções necessárias epatch e epatch_user de um arquivo de origem com muitas funções, disponibilizá-las no shell atual, executar uma delas (que, por sua vez, usa as outras ) e remova-os. O objetivo final é solucionar a limitação do Gentoo de que apenas ebuilds herdando eutils tenham acesso a epatch_user .

    
por Pavel Šimerda 15.12.2014 / 13:07

3 respostas

3

Você pode usar a substituição de processos

source /dev/stdin < <(echo -ne 'f() { echo a; }\n')

ou

source <(echo -ne 'f() { echo a; }\n')

Isso funciona no bash 4.1.5, por alguma razão, não funciona em 3.2.48.

    
por 15.12.2014 / 17:43
4

Cada parte dos pipelines é executada em processos separados ou sub-pasta própria . Então, quando seus pipelines terminarem, seu shell atual não sabe nada sobre a função f .

Com bash ( ksh , pdksh , zsh , mksh ou shell que suporta Here-String ), você pode usar:

$ source /dev/stdin <<<'f() { echo a; }'
$ f
a

POSIXly, você deve usar aqui documento e ponto :

$ . /dev/stdin <<'EOF'
> f() { echo a; }
> EOF

$ f
a
    
por 15.12.2014 / 18:27
2

Os comandos em um pipe são processos separados, portanto, a definição de função originada de /dev/stdin é perdida assim que o pipe é concluído. É por isso que o pipe mostra resultados diferentes para o uso do arquivo temporário.

No seu caso de uso, o eval sugerido por PM 2Ring seria o caminho a seguir.

    
por 15.12.2014 / 16:17