Oposto ao comando `source`

9

Eu uso o sourcecomando no meu script bash para ler / imprimir os valores das variáveis

more linuxmachines_mount_point.txt

export linuxmachine01="sdb sdc sdf sdd sde sdg"
export linuxmachine02="sde sdd sdb sdf sdc"
export linuxmachine03="sdb sdd sdc sde sdf"
export linuxmachine06="sdb sde sdf sdd"

source  linuxmachines_mount_point.txt

echo $linuxmachine01
sdb sdc sdf sdd sde sdg

Qual é o oposto de sourcepara desarmar as variáveis?

Resultados esperados

echo $linuxmachine01

< no output >
yael
fonte
14
Não é isso sourceque está definindo as variáveis ​​em seu ambiente, mas as exportinstruções no arquivo que você source. Portanto, o oposto de sourcepoderia ser source, se você tiver sourceum arquivo diferente com unsetas mesmas variáveis.
user4556274
2
yel, não use exportações, apenas use name = "val". A exportação é para variáveis ​​de script para binários (o ambiente).
Ctrl-d
1
Relacionado: unix.stackexchange.com/q/382618/117549
Jeff Schaller
2
Isto é impossível. O conceito que você está procurando é chamado de Computação Reversível . As linguagens de programação precisam ser projetadas especificamente com algumas restrições severas para serem reversíveis. O Bash não é uma dessas linguagens de programação.
Jörg W Mittag
1
@yael, isso é falso (e você obviamente nunca executou o teste que está mandando o ctrl-d fazer); você absolutamente não precisa do exports. Tudo o que exportfaz é copiar os valores no ambiente - mas eles estão presentes como variáveis ​​de shell, independentemente de serem ou não definidos como variáveis ​​de ambiente. Além disso, a definição de variáveis ​​de ambiente desnecessárias reduz o comprimento máximo da linha de comando, pois elas são armazenadas no mesmo espaço (limitado!) Por processo.
Charles Duffy

Respostas:

21

Usando um subshell (recomendado)

Execute o comando de origem em um subshell:

(
source linuxmachines_mount_point.txt
cmd1 $linuxmachine02
other_commands_using_variables
etc
)
echo $linuxmachine01  # Will return nothing

Subcamadas são definidas por parênteses: (...). Quaisquer variáveis ​​de shell definidas no subshell são esquecidas quando o subshell termina.

Usando não configurado

Isso desativa qualquer variável exportada por linuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' diz ao awk para usar qualquer combinação de espaços e sinais de igual como separador de campos.

  • /^export/{print $2}

    Isso indica ao awk para selecionar as linhas que começam com exporte depois imprimir o segundo campo.

  • unset $(...)

    Isso executa o comando dentro $(...), captura seu stdout e desativa todas as variáveis ​​nomeadas por sua saída.

John1024
fonte
por que não usar isso - para i no arquivo `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; desmarque $ i; feito ? (mais simples para desconfigurar)
yael
2
@yael Isso usa um processo extra e um loop quando nenhum deles é necessário. As opiniões podem variar, mas não vejo isso mais simples. Além disso e potencialmente perigoso, assume que cada linha fileé uma declaração de exportação.
John1024
8
@yael Além disso, desmarcar variáveis ​​e desfazer outros efeitos colaterais do código é exatamente para que servem os subshells. Eles fazem isso de forma simples e confiável. A menos que exista algum motivo especial, subshells são o que você deve usar.
John1024
4

Você não pode un sourceo script.

O que você pode fazer é armazenar todas as variáveis ​​exportadas em um arquivo temporário, compará-las com as variáveis ​​após a origem do script e, em seguida, remover o excesso com unset, por exemplo:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"
jimmij
fonte
por que não usar isso - para i no arquivo `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; desmarque $ i; feito ? (mais simples para desconfigurar)
yael
@yael funcionará apenas se o script contiver apenas exports.
jimmij
o que você quer dizer com "exportar s", meu arquivo inclui linuxmachine01 = "sdb sdc sdf sdd sde sdg" e assim por diante, e quando eu uso o loop do awk, ela desativa a variável sem problemas
yael
@yael Não sei exatamente como é o seu arquivo, por isso dei uma resposta geral, por exemplo, e se o script contiver um comentário na parte superior dizendo "# Aqui estão algumas variáveis ​​a serem exportadas com pontos de montagem".
jimmij
2

Você pode usar o unsetcomando para "esquecer" variáveis.

francois P
fonte
O arquivo pode estar em máquinas diff, então como desarmar as segundas variáveis ​​no arquivo?
yael
unset variablename irá esquecê-lo (você pode encontrá-lo explicado na página de manual do bash / sh / ksh / zsh) demo dele: pastebin.com/MGQyTZEA
francois P
sim, mas porque as variáveis poderia ser diff, necessidade script bash para fazê-lo, ler a variável do arquivo e Desativar eles, ele não pode ser estático, porque variável são desconhecidos
yael
em seguida, grep suas linhas de exportação (recortar) para listar variáveis ​​do arquivo a ser desabilitado para exportação linuxmachine06 = "sdb sde sdf sdd", em seguida, você obtém linuxmachine06 como um nome para desmarcar exemplo: pastebin.com/M9eCtLc7 como você vê o comando desmarcar aqui sabe o nome da variável que é conhecida apenas no final
francois P
ok, usarei esta sintaxe para desarmar - para i no arquivo `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; desmarque $ i; done
yael
2

A solução mais simples para obter a saída que você espera (nada) é declarar novamente a variável como vazia:

$ export linuxmachine01="sdb sdc sdf sdd sde sdg"
$ echo "$linuxmachine01"
sdb sdc sdf sdd sde sdg

$ linuxmachine01=""
$ echo "$linuxmachine01"
$

Obviamente, a variável ainda está definida (e exportada), vazia, mas definida:

$ declare -p linuxmachine01
declare -x linuxmachine01=""

Para remover corretamente a variável do ambiente e do shell em execução, você deve usar o unset (da maneira recomendada):

$ unset linuxmachine01
$ declare -p linuxmachine01
bash: declare: linuxmachine01: not found
$ echo "$linuxmachine01"
$
Isaac
fonte
1

A maneira mais simples de fazer isso é modificar seu script, para que ele também defina um comando para desfazer o efeito do script:

export linuxmachine01="sdb sdc sdf sdd sde sdg"
export linuxmachine02="sde sdd sdb sdf sdc"
export linuxmachine03="sdb sdd sdc sde sdf"
export linuxmachine06="sdb sde sdf sdd"
alias linuxmachines_mount_point='for v in linuxmachine01 linuxmachine02 linuxmachine03 linuxmachine04; do unset $v; done; unalias linuxmachines_mount_point'
Lie Ryan
fonte
Por que um apelido em vez de uma função? Observe que os aliases estão desativados em shells não interativos por padrão; portanto, pronto para uso, isso não funcionará em um script.
Charles Duffy
... na verdade, isso seria ainda mais fácil se definíssemos apenas uma variável e, portanto, tivéssemos apenas uma para desarmar:, declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )então é apenas unset linuxmachinespara reverter.
Charles Duffy
@ CharlesDuffy: tanto o alias quanto a função são bons para esse fim. A razão pela qual não sugiro colocar tudo em uma variável é que definir um comando desfazer é muito mais genérico. Você pode definir não apenas variáveis, mas também funções, aliases, configurações do sistema, configurações do terminal etc. Ele fornece uma melhor abstração, pois você não precisa se preocupar com o conteúdo exato do comando desfazer.
Lie Ryan
Acredito que meu argumento acima é que os aliases não são bons para o objetivo, se "o objetivo" incluir uso não-interativo (ou seja, invocação de scripts).
Charles Duffy
0

Você pode escrever seu linuxmachines_mount_point.txt assim

test "$linuxmachine01" && unset -v linuxmachine01 || linuxmachine01="sdb sdc sdf sdd sde sdg"

Quando você precisa de suas variáveis

source linuxmachines_mount_point.txt

Quando você deseja remover as variáveis

source linuxmachines_mount_point.txt
ctac_
fonte
0

Se você estiver usando o sourcecomando para ativar um VirtualEnvironment, você pode sair usando o comando deactivate.

Wolf Elkan
fonte