Przeciwnie do polecenia `source`

9

Korzystam z sourcepolecenia w skrypcie bash, aby odczytać / wydrukować wartości zmiennych

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

Czym jest przeciwieństwo source, aby rozbroić zmienne?

Oczekiwane rezultaty

echo $linuxmachine01

< no output >
Yael
źródło
14
To nie sourcejest ustawianie zmiennych w twoim środowisku, ale exportinstrukcje w pliku, które ty source. Więc sourcemoże być odwrotnie source, jeśli masz sourceinny plik, który zawiera unsette same zmienne.
user4556274,
2
yael, nie używaj eksportu, po prostu użyj name = "val". Eksport dotyczy zmiennych skryptu do plików binarnych (środowisko).
ctrl-d
1
Powiązane: unix.stackexchange.com/q/382618/117549
Jeff Schaller
2
To jest niemożliwe. Koncepcja, której szukasz, nosi nazwę Reversible Computing . Języki programowania muszą być specjalnie zaprojektowane z pewnymi poważnymi ograniczeniami, aby były odwracalne. Bash nie jest jednym z tych języków programowania.
Jörg W Mittag,
1
@yael, to nieprawda (i oczywiście nigdy nie przeprowadziłeś testu, o którym mówisz ctrl-d); absolutnie nie potrzebujesz exports. Wystarczy exportskopiować wartości do środowiska - ale są one obecne jako zmienne powłoki, niezależnie od tego, czy są również zdefiniowane jako zmienne środowiskowe. Co więcej, zdefiniowanie niepotrzebnych zmiennych środowiskowych skraca maksymalną długość wiersza poleceń, ponieważ są one przechowywane w tej samej (ograniczonej!) Przestrzeni na proces.
Charles Duffy

Odpowiedzi:

21

Korzystanie z podpowłoki (zalecane)

Uruchom polecenie źródłowe w podpowłoce:

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

Podpowłok są zdefiniowane przez parens: (...). Wszelkie zmienne powłoki ustawione w podpowłoce są zapominane po zakończeniu podpowłoki.

Używam unset

To powoduje rozbrojenie dowolnej zmiennej eksportowanej przez linuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' mówi awk, aby używał dowolnej kombinacji spacji i znaków równości jako separatora pól.

  • /^export/{print $2}

    To każe awk wybrać linie zaczynające się od, exporta następnie wydrukować drugie pole.

  • unset $(...)

    To uruchamia polecenie wewnątrz $(...), przechwytuje jego standardowe wyjście i resetuje wszelkie zmienne nazwane przez jego dane wyjściowe.

John1024
źródło
dlaczego tego nie użyć - dla i w pliku `awk '{print 2 $} | awk -F "=" '{print 1 $}' '; nie rozbieraj $ i; gotowy ? (prostsze dla
rozbrojenia
2
@yael Wykorzystuje dodatkowy proces i pętlę, gdy żadna z nich nie jest potrzebna. Opinie mogą się różnić, ale nie uważam tego za prostsze. Również i potencjalnie niebezpieczne, zakłada, że ​​każda linia w filejest wywozem.
John1024,
8
@yael Również rozbrojenie zmiennych i cofnięcie innych skutków ubocznych kodu jest dokładnie tym, do czego służą podpowłoki. Robią to w prosty i niezawodny sposób. O ile nie ma innego specjalnego powodu, należy użyć podpowłoki.
John1024,
4

Nie możesz odblokować sourceskryptu.

Możesz zapisać wszystkie wyeksportowane zmienne w pliku tymczasowym, porównać je ze zmiennymi po źródle skryptu, a następnie usunąć przepełnienie unset, np .:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"
jimmij
źródło
dlaczego tego nie użyć - dla i w pliku `awk '{print 2 $} | awk -F "=" '{print 1 $}' '; nie rozbieraj $ i; gotowy ? (prostsze dla
rozbrojenia
@yael będzie działać tylko wtedy, gdy skrypt zawiera tylko exports.
jimmij
co masz na myśli "eksportuj s", mój plik zawiera linuxmachine01 = "sdb sdc sdf sdd sde sdg" i tak dalej, a kiedy używam pętli awk, bezproblemowo
ustawia
@yael Nie wiem, jak dokładnie wygląda twój plik, więc podałem ogólną odpowiedź, na przykład co jeśli skrypt zawiera komentarz na górze, mówiąc: „# Oto niektóre zmienne do wyeksportowania z punktami montowania”.
jimmij
2

Możesz użyć unsetpolecenia, aby „zapomnieć” o zmiennych.

francois P.
źródło
plik może być z różnymi maszynami, więc jak rozbroić drugie zmienne w pliku?
yael
unset variablename zapomni o tym (można to wyjaśnić na stronie podręcznika użytkownika bash / sh / ksh / zsh) demo: pastebin.com/MGQyTZEA
francois P
tak, ale ponieważ zmienne mogą być różne, skrypt bash musi to zrobić, odczytując zmienną z pliku i usuwając ją, nie może być statyczny, ponieważ zmienne są nieznane
yael 30.12.17
następnie grep eksportuj linie (wytnij), aby wyświetlić zmienne z pliku do rozbrojenia eksport linuxmachine06 = "sdb sde sdf sdd", a następnie otrzymasz linuxmachine06 jako nazwę do rozbrojenia przykładu: pastebin.com/M9eCtLc7, gdy zobaczysz polecenie unset tutaj nie znam nazwy zmiennej, która jest znana tylko na końcu
francois P
ok użyję tej składni, aby ją rozbroić - dla i w pliku `awk '{print $ 2}' | awk -F "=" '{print 1 $}' '; nie rozbieraj $ i; gotowe
yael
2

Najprostszym rozwiązaniem, aby uzyskać oczekiwany wynik (nic), jest ponowne zadeklarowanie zmiennej jako pustej:

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

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

Oczywiście zmienna jest nadal zdefiniowana (i eksportowana), pusta, ale zdefiniowana:

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

Aby poprawnie usunąć zmienną zarówno ze środowiska, jak i działającej powłoki, powinieneś użyć unset (zalecany sposób):

$ unset linuxmachine01
$ declare -p linuxmachine01
bash: declare: linuxmachine01: not found
$ echo "$linuxmachine01"
$
Izaak
źródło
1

Najprostszym sposobem na to jest zmodyfikowanie skryptu, aby zdefiniował także polecenie cofnięcia efektu skryptu:

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
źródło
Dlaczego alias zamiast funkcji? Zauważ, że aliasy są domyślnie wyłączone w nieinteraktywnych powłokach, więc po wyjęciu z pudełka nie zadziała to w skrypcie.
Charles Duffy
... właściwie byłoby to jeszcze łatwiejsze, gdybyśmy zdefiniowali tylko jedną zmienną, a zatem mieliśmy tylko jedną opcję do rozbrojenia: declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )wtedy wystarczy unset linuxmachinescofnąć.
Charles Duffy
@CharlesDuffy: zarówno alias, jak i funkcja są w tym celu w porządku. Powodem, dla którego nie sugeruję umieszczania wszystkiego w jednej zmiennej, jest to, że definiowanie polecenia cofania jest o wiele bardziej ogólne. Możesz zdefiniować nie tylko zmienne, ale także funkcje, aliasy, ustawienia systemowe, ustawienia terminala itp. Zapewnia lepszą abstrakcję, ponieważ nie musisz dbać o dokładną treść polecenia cofnij.
Lie Ryan,
Uważam, że moja powyższa uwaga jest taka, że ​​aliasy nie są odpowiednie do tego celu, jeśli „cel” obejmuje użycie nieinteraktywne (tj. Wywołanie ze skryptów).
Charles Duffy
0

Możesz napisać swój linuxmachines_mount_point.txt w ten sposób

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

Kiedy potrzebujesz swoich zmiennych

source linuxmachines_mount_point.txt

Kiedy chcesz usunąć zmienne

source linuxmachines_mount_point.txt
ctac_
źródło
0

Jeśli używasz sourcepolecenia do aktywacji a VirtualEnvironment, możesz wyjść z niego za pomocą polecenia deactivate.

Wolf Elkan
źródło