Como posso exportar uma variável sem perder seu valor?

6

Digamos que eu exportei uma variável:

foo=bar
export foo

Agora, gostaria de exportá-lo novamente. Isto é, se eu fizer sh -c 'echo "$foo"' eu não deveria obter bar . foo não deve aparecer no ambiente sh -c . sh -c é apenas um exemplo, uma maneira fácil de mostrar a presença de uma variável. O comando pode ser qualquer coisa - pode ser algo cujo comportamento é afetado simplesmente pela presença da variável em seu ambiente.

Eu posso:

  1. unset da variável e perdê-la
  2. Remova-o usando env para cada comando: env -u foo sh -c 'echo "$foo"'
    • impraticável se você quiser continuar usando o shell atual por um tempo.

Idealmente, eu gostaria de manter o valor da variável, mas não mostrá-la de forma alguma em um processo filho, nem mesmo como uma variável vazia.

Eu acho que eu poderia fazer:

otherfoo="$foo"; unset foo; foo="$otherfoo"; unset otherfoo

Isso arrisca pisar sobre otherfoo , se já existir.

Esse é o único caminho? Existem maneiras padronizadas?

    
por muru 01.01.2016 / 21:45

3 respostas

5

Não há um caminho padrão.

Você pode evitar o uso de uma variável temporária usando uma função. A seguinte função tem o cuidado de manter as variáveis não definidas não definidas e as variáveis vazias vazias. No entanto, ele não suporta recursos encontrados em alguns shells, como variáveis somente leitura ou digitadas.

unexport () {
  while [ "$#" -ne 0 ]; do
    eval "set -- \"\${$1}\" \"\${$1+set}\" \"\$@\""
    if [ -n "$2" ]; then
      unset "$3"
      eval "$3=\"
    fi
    shift; shift; shift
  done
}
unexport foo bar

Em ksh, bash e zsh, você pode não exportar uma variável com typeset +x foo . Isso preserva propriedades especiais, como tipos, por isso é preferível usá-lo. Eu acho que todos os shells que têm um typeset embutido tem typeset +x .

case $(LC_ALL=C type typeset 2>&1) in
  typeset\ *\ builtin) unexport () { typeset +x -- "$@"; };;
  *) unexport () { … };; # code above
esac
    
por 02.01.2016 / 01:16
4

EDITAR: Somente para bash , conforme apontado nos comentários:

A opção -n para export remove a propriedade export de cada nome dado. (Veja help export .)

Então para bash , o comando que você quer é: export -n foo

    
por 01.01.2016 / 22:17
2

Eu escrevi uma função POSIX semelhante, mas isso não arrisca a execução de código arbitrário:

unexport()
    while case ${1##[0-9]*} in                   ### rule out leading numerics
          (*[!_[:alnum:]]*|"")                   ### filter out bad|empty names
          set "" ${1+"bad name: '$1'"}           ### prep bad name error
          return ${2+${1:?"$2"}}                 ### fail w/ above err or return 
          esac
    do    eval  set '"$'"{$1+$1}"'" "$'"$1"'" "$'@\" ###  $1 = (  $1+ ? $1 : "" )
          eval  "${1:+unset $1;$1=\;} shift 3"     ### $$1 = ( $1:+ ? $2 : -- )
    done

Ele também lidará com tantos argumentos quanto quiser fornecer. Se um argumento for um nome válido que não esteja definido de outra maneira, ele será silenciosamente ignorado. Se um argumento é um nome ruim, ele grava em stderr e pára conforme apropriado, embora qualquer nome válido anterior a um inválido em sua linha de comando ainda seja processado.

Eu pensei em outro jeito. Eu gosto muito disso.

unexport()
        while   unset OPTARG; OPTIND=1           ### always work w/ $1
                case  ${1##[0-9]*}    in         ### same old same old
                (*[!_[:alnum:]]*|"")             ### goodname && $# > 0 || break
                    ${1+"getopts"} : "$1"        ### $# ? getopts : ":"
                    return                       ### getopts errored or ":" didnt
                esac
        do      eval   getopts :s: '"$1" -"${'"$1+s}-\$$1\""
                eval   unset  "$1;  ${OPTARG+$1=\${OPTARG}#-}"
                shift
        done

Bem, ambos usam muitas das mesmas técnicas. Basicamente, se uma var de shell não estiver definida, uma referência a ela não será expandida com uma expansão de parâmetro + . Mas se for definido - independentemente do seu valor - uma expansão de parâmetro como: ${parameter+word} será expandida para word - e não para o valor da variável. E assim, as variáveis da shell fazem o autoteste e auto-substituem no sucesso.

Eles também podem auto-reprovar . Na função principal, se um nome inválido for encontrado, movo $1 para $2 e deixo $1 null porque a próxima coisa que faço é return success se todos os args tiverem sido processados e o loop tiver terminado ou, se o argumento for inválido, o shell expandirá o $2 para $1:? , o que eliminará um shell com script e retornará uma interrupção para um interativo ao gravar word em stderr.

No segundo, getopts faz as atribuições. E não irá atribuir um nome ruim - em vez disso, escreva para gravar uma mensagem de erro padrão para stderr. Além disso, ele salva o valor do argumento em $OPTARG se o argumento era o nome de uma variável set em primeiro lugar. Então, depois de fazer getopts , tudo que é necessário é eval a expansão de OPTARG na atribuição apropriada.

    
por 02.01.2016 / 05:02