En face de la commande `source`

9

J'utilise la sourcecommande dans mon script bash pour lire / imprimer les valeurs des variables

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

Quel est le contraire sourcepour désarmer les variables?

Résultats attendus

echo $linuxmachine01

< no output >
Yael
la source
14
Ce n'est pas sourcecela qui définit les variables dans votre environnement, mais les exportinstructions dans le fichier que vous source. Donc, l'opposé de sourcepourrait être source, si vous avez sourceun fichier différent qui unsetcontient toutes les mêmes variables.
user4556274
2
yael, n'utilisez pas d'export, utilisez simplement name = "val". L'exportation concerne les variables script vers binaires (l'environnement).
ctrl-d
1
Connexe: unix.stackexchange.com/q/382618/117549
Jeff Schaller
2
C'est impossible. Le concept que vous recherchez s'appelle l' informatique réversible . Les langages de programmation doivent être spécifiquement conçus avec certaines restrictions sévères afin d'être réversibles. Bash n'est pas un de ces langages de programmation.
Jörg W Mittag
1
@yael, c'est faux (et vous n'avez évidemment jamais exécuté le test que vous dites à ctrl-d de faire); vous n'avez absolument pas besoin du par export. Il exportsuffit de copier les valeurs dans l'environnement - mais elles sont présentes en tant que variables shell, qu'elles soient ou non définies comme variables d'environnement également. De plus, la définition de variables d'environnement inutiles raccourcit la longueur maximale de votre ligne de commande, car elles sont stockées dans le même espace (limité!) Par processus.
Charles Duffy

Réponses:

21

Utilisation d'un sous-shell (recommandé)

Exécutez la commande source dans un sous-shell:

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

Sous - couches sont définies par parens: (...). Toutes les variables de shell définies dans le sous-shell sont oubliées à la fin du sous-shell.

Utiliser unset

Cela supprime toute variable exportée par linuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' indique à awk d'utiliser n'importe quelle combinaison d'espaces et de signes égaux comme séparateur de champ.

  • /^export/{print $2}

    Cela indique à awk de sélectionner les lignes commençant par exportpuis d'imprimer le deuxième champ.

  • unset $(...)

    Cela exécute la commande à l'intérieur $(...), capture sa sortie standard et désactive toutes les variables nommées par sa sortie.

John1024
la source
pourquoi ne pas l'utiliser - pour i dans le fichier `awk '{print $ 2}' | awk -F "=" '{print $ 1}' '; ne définissez pas $ i; terminé ? (plus simple pour unset)
yael
2
@yael qui utilise un processus supplémentaire et une boucle quand aucun n'est nécessaire. Les opinions peuvent varier mais je ne vois pas cela comme plus simple. Également et potentiellement dangereux, il suppose que chaque ligne fileest une déclaration d'exportation.
John1024
8
@yael En outre, la suppression des variables et l'annulation d'autres effets secondaires du code sont exactement ce à quoi servent les sous-coquilles. Ils le font de manière simple et fiable. À moins qu'il n'y ait une raison particulière, les sous-coquilles sont ce que vous devriez utiliser.
John1024
4

Vous ne pouvez pas annuler sourcele script.

Ce que vous pouvez faire est de stocker toutes les variables exportées dans un fichier temporaire, de les comparer avec des variables après la source du script, puis de supprimer le débordement avec unset, par exemple:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"
jimmij
la source
pourquoi ne pas l'utiliser - pour i dans le fichier `awk '{print $ 2}' | awk -F "=" '{print $ 1}' '; ne définissez pas $ i; terminé ? (plus simple pour unset)
yael
@yael cela ne fonctionnera que si le script ne contient que exports.
jimmij
ce que vous voulez dire « exportation s », mon fichier include linuxmachine01 = « salésien sdc sdf sdd SDG sde » et ainsi de suite, et quand j'utilise la boucle de awk sa unset la variable sans problèmes
yael
@yael Je ne sais pas exactement à quoi ressemble votre fichier, j'ai donc donné une réponse générale, par exemple si le script contient un commentaire en haut disant "# Voici quelques variables à exporter avec des points de montage.".
jimmij
2

Vous pouvez utiliser la unsetcommande pour "oublier" les variables.

francois P
la source
le fichier pourrait être avec des machines de diff, alors comment supprimer les secondes variables du fichier?
yael
unset variablename l'oubliera (vous pouvez le trouver expliqué dans la page de manuel bash / sh / ksh / zsh) démo: pastebin.com/MGQyTZEA
francois P
oui mais parce que les variables peuvent être différentes, le script bash doit le faire en lisant la variable du fichier et en les désinstallant, il ne peut pas être statique car les variables sont inconnues
yael
puis grep vos lignes d'export (cut) pour lister les variables du fichier à annuler export linuxmachine06 = "sdb sde sdf sdd" puis vous obtenez linuxmachine06 comme nom à désactiver exemple: pastebin.com/M9eCtLc7 comme vous voyez la commande unset ici doen ne connais pas le nom de la variable, il n'est connu qu'à la fin
francois P
ok je vais utiliser cette syntaxe afin de désactiver - pour i dans le fichier `awk '{print $ 2}' | awk -F "=" '{print $ 1}' '; ne définissez pas $ i; fait
yael
2

La solution la plus simple pour obtenir la sortie que vous attendez (rien) est de déclarer à nouveau la variable comme vide:

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

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

Bien sûr, la variable est toujours définie (et exportée), vide mais définie:

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

Pour supprimer correctement la variable de l'environnement et du shell en cours d'exécution, vous devez utiliser unset (la manière recommandée):

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

La façon la plus simple de le faire est de modifier votre script afin qu'il définisse également une commande pour annuler l'effet du 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
la source
Pourquoi un alias plutôt qu'une fonction? Notez que les alias sont désactivés par défaut dans les shells non interactifs, donc hors de la boîte, cela ne fonctionnera pas dans un script.
Charles Duffy,
... en fait, ce serait encore plus facile si nous ne définissions qu'une seule variable, et donc n'avions qu'une seule à désactiver:, declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )alors c'est juste unset linuxmachinespour revenir.
Charles Duffy
@CharlesDuffy: à la fois l'alias et la fonction conviennent à cet effet. La raison pour laquelle je ne suggère pas de tout mettre dans une variable est que la définition d'une commande d'annulation est beaucoup plus générique. Vous pouvez non seulement définir des variables, mais aussi des fonctions, des alias, des paramètres système, des paramètres de terminal, etc. Il fournit une meilleure abstraction car vous n'avez pas à vous soucier du contenu exact de la commande d'annulation.
Lie Ryan
Je crois que mon point ci-dessus est que les alias ne conviennent pas à la fin, si "la fin" inclut une utilisation non interactive (c'est-à-dire une invocation à partir de scripts).
Charles Duffy
0

Vous pouvez écrire votre linuxmachines_mount_point.txt comme ceci

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

Quand vous avez besoin de vos variables

source linuxmachines_mount_point.txt

Lorsque vous souhaitez supprimer les variables

source linuxmachines_mount_point.txt
ctac_
la source
0

Si vous utilisez la sourcecommande pour activer un VirtualEnvironment, vous pouvez le quitter à l'aide de la commande deactivate.

Wolf Elkan
la source