Напротив команды `source`

9

Я использую sourceкоманду в моем скрипте bash для чтения / печати значений переменных

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

Что является противоположностью для sourceтого, чтобы сбросить переменные?

Ожидаемые результаты

echo $linuxmachine01

< no output >
Яэль
источник
14
Это не sourceто, что устанавливает переменные в вашей среде, а exportутверждения в файле, который вы source. Таким образом, противоположность sourceможет быть source, если у вас sourceдругой файл, в котором unsetвсе переменные.
user4556274
2
да, не используйте экспорт, просто используйте name = "val". Экспорт для переменных сценария в двоичные файлы (среда).
ctrl-d
1
Связанный: unix.stackexchange.com/q/382618/117549
Джефф Шаллер
2
Это невозможно. Концепция, которую вы ищете, называется Reversible Computing . Языки программирования должны быть специально разработаны с некоторыми жесткими ограничениями, чтобы быть обратимыми. Bash не является одним из тех языков программирования.
Йорг Миттаг
1
@yael, это не соответствует действительности (и вы, очевидно, никогда не запускали тест, который вы говорите ctrl-d); вам абсолютно не нужны exportс. Все, что exportнужно - это скопировать значения в среду, но они присутствуют как переменные оболочки, независимо от того, определены они или нет как переменные среды. Более того, определение ненужных переменных среды сокращает максимальную длину командной строки, поскольку они хранятся в одном (ограниченном!) Пространстве для каждого процесса.
Чарльз Даффи

Ответы:

21

Использование подоболочки (рекомендуется)

Запустите исходную команду в подоболочке:

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

Подоболочки определяются круглые скобки: (...). Любые переменные оболочки, установленные в подоболочке, будут забыты, когда она будет завершена.

Использование unset

Это отменяет любую переменную, экспортируемую linuxmachines_mount_point.txt:

unset $(awk -F'[ =]+' '/^export/{print $2}' linuxmachines_mount_point.txt)
  • -F'[ =]+' говорит awk использовать любую комбинацию пробелов и знаков равенства в качестве разделителя полей.

  • /^export/{print $2}

    Это говорит awk выбирать строки, которые начинаются с, exportа затем печатать второе поле.

  • unset $(...)

    Это запускает команду внутри $(...), захватывает ее стандартный вывод и сбрасывает все переменные, названные ее выводом.

John1024
источник
почему бы не использовать это - потому что я в файле `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; сделать unset $ i; сделанный ? (проще для unset)
яэль
2
@yael, который использует дополнительный процесс и цикл, когда ни один не нужен. Мнения могут отличаться, но я не считаю это проще. Также и потенциально опасно, предполагается, что каждая строка fileявляется оператором экспорта.
John1024
8
@yael Кроме того, удаление переменных и удаление других побочных эффектов кода - это как раз то, для чего нужны подоболочки. Они делают это просто и надежно. Если нет какой-либо особой причины, вам следует использовать подоболочки.
John1024
4

Вы не можете удалить sourceсценарий.

Что вы можете сделать, это сохранить все экспортированные переменные во временном файле, сравнить их с переменными после того, как сценарий получен, а затем удалить переполнение unset, например:

export > temp_file
source myscript

#... do some stuff

unset "$(comm -3 <(sort temp_file) <(export | sort) | awk -F'[ =]' '{print $3}' | tr '\n' ' ')"
jimmij
источник
почему бы не использовать это - потому что я в файле `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; сделать unset $ i; сделанный ? (проще для unset)
яэль
@yael будет работать только если скрипт содержит только exports.
Джимми
что вы имеете в виду "export s", мой файл включает linuxmachine01 = "sdb sdc sdf sdd sde sdg" и так далее, и когда я использую цикл awk, он
сбрасывает
@yael Я не знаю, как именно выглядит ваш файл, поэтому я дал общий ответ, например, что, если скрипт содержит комментарий вверху: «# Вот некоторая переменная для экспорта с точками монтирования».
Джимми
2

Вы можете использовать unsetкоманду, чтобы «забыть» переменные.

Франсуа П
источник
файл может быть с разными машинами, так как сбросить вторые переменные в файле?
Яэль
unset variablename забудет об этом (вы можете найти его объяснение на странице руководства bash / sh / ksh / zsh). Демонстрация этого: pastebin.com/MGQyTZEA
francois P
да, но поскольку переменные могут быть diff, bash-скрипт должен делать это, читая переменную из файла и сбрасывая их, он не может быть статическим, потому что переменная неизвестна
yael
затем GREP ваш экспорт строк (разрезанные) в список переменных из файла будут снят с охраной экспорта linuxmachine06 = «SDB СДУ SDF SDD» , то вы получите linuxmachine06 как имя на отключенные например: pastebin.com/M9eCtLc7 , как вы видите отключенную команду здесь Doen Имя переменной известно только в конце
Франсуа П
Хорошо, я буду использовать этот синтаксис для сброса - я в файле `awk '{print $ 2}' | awk -F "=" '{print $ 1}' `; сделать unset $ i; сделано
яэль
2

Самое простое решение получить ожидаемый результат (ничего) - повторно объявить переменную как пустую:

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

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

Конечно, переменная все еще определена (и экспортирована), пустая, но определенная:

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

Чтобы правильно удалить переменную как из среды, так и из запущенной оболочки, вы должны использовать unset (рекомендуемый способ):

$ unset linuxmachine01
$ declare -p linuxmachine01
bash: declare: linuxmachine01: not found
$ echo "$linuxmachine01"
$
Исаак
источник
1

Самый простой способ сделать это - изменить скрипт, чтобы он также определил команду для отмены эффекта скрипта:

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'
Ли Райан
источник
Почему псевдоним, а не функция? Обратите внимание, что псевдонимы отключены в неинтерактивных оболочках по умолчанию, поэтому в сценарии это не будет работать.
Чарльз Даффи
... на самом деле, это было бы еще проще, если бы мы определили только одну переменную и, следовательно, имели только одну для сброса: declare -A linuxmachines=( [01]="sdb sdc sdf" [02]="sde sdd sdb" [03]="whatever" )тогда это просто unset linuxmachinesдля возврата.
Чарльз Даффи
@CharlesDuffy: псевдоним и функция подходят для этой цели. Причина, по которой я не предлагаю помещать все в одну переменную, состоит в том, что определение команды отмены является гораздо более общим. Вы можете отменить не только переменные, но также функции, псевдонимы, системные настройки, настройки терминала и т. Д. Это обеспечивает лучшую абстракцию, поскольку вам не нужно заботиться о точном содержании команды отмены.
Ложь Райану
Я полагаю, что моя точка зрения выше состоит в том, что псевдонимы не подходят для этой цели, если «цель» включает неинтерактивное использование (то есть вызов из сценариев).
Чарльз Даффи
0

Вы можете написать свой linuxmachines_mount_point.txt следующим образом

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

Когда вам нужны ваши переменные

source linuxmachines_mount_point.txt

Когда вы хотите удалить переменные

source linuxmachines_mount_point.txt
ctac_
источник
0

Если вы используете sourceкоманду для активации VirtualEnvironment, вы можете выйти из нее с помощью команды deactivate.

Волк элькан
источник