3

To declare a variable in Bash, say in a Bash script-file (that doesn't include Bash function), I do for example x=y and when I finish using it inside that script-file I do unset x.

Is there a way (without using a function), to unset the variable after say 5 minutes, both in one line? A plausible approach might be x=y && echo "unset x" | at now + 5 minutes.

In this particular case I run the script-file directly in the terminal by copy-pasting its content from GitHub to terminal. This falls under sourcing I assume".


Given I use GitHub, an alternative might be executing a raw version of the script-file directly from GitHub with bash in a separate shell as follows, but I don't like that way because it can't be user/repo/branch/path/file-agnostic:

wget -O - https://raw.githubusercontent.com/<username>/<repo>/<branch>/<path>/<file> | bash
3
  • 1
    You need to do unset x only if you are sourcing the script file. Otherwise the script runs in a subshell and does not affect your shell environment, so you don't need to unset it. I use parentheses to run one-liners with temporary variables on the command line all the time, like ( for i in {1..20}; do dosomething; done), and after I execute this command I don't have $i in my shell. Dec 13, 2018 at 3:05
  • If you're trying to do that for "security" purposes (ie. that var holds a password), then keep in mind that unsetting a variable does not guarantee in any way that its content will be scrubbed from memory. Simply put, keeping sensitive data in plain text in shell variables is not something that should be done for 5 secs, 5 minutes or 5 hours.
    – user313992
    Dec 13, 2018 at 4:13
  • 1
    @WeijunZhou I updated the question due to your comment.
    – user149572
    Dec 13, 2018 at 15:58

4 Answers 4

10

You can't use at jobs because they run in a different context, and can't affect the current shell.

But we can do something similar. This code will trigger an alarm signal, which we can catch and perform action on

#!/bin/bash

x=100

trap 'unset x' SIGALRM

mypid=$$

( /bin/sleep 3 ; kill -ALRM $mypid) &

for a in 1 2 3 4 5 6
do
  echo Now x=$x
  sleep 1
done

This example is only 3 seconds long to demonstrate the solution; you can pick your delay as you need.

In action:

Now x=100
Now x=100
Now x=100
Now x=
Now x=
Now x=

You can easily make it one line with ;...

3
  • Wow - great minds think alike -- and within 30 seconds of each other! :)
    – Jeff Schaller
    Dec 13, 2018 at 2:09
  • @JeffSchaller I noticed that :-) Dec 13, 2018 at 2:10
  • 1
    @JeffSchaller I rolled back your edit; I specifically put a 3 second pause in as an example; a 300 second (5minute) sleep would mean the for loop won't demonstrate the solution working. I'll edit the answer to make that clear. Dec 13, 2018 at 2:14
8

Sure:

trap 'unset x; trap - USR1' USR1; { sleep 5m; kill -USR1 $$; } &

This sets a trap on the USR1 signal, then (cheating with a semicolon to put it on one line) groups together the sleep and kill commands into a background job. When that job completes, it will send the USR1 signal to the current shell, which will execute the trap. The trap unsets x and then clears the trap.

No functions!

3

With your revised question, based around the command line and not a script, your simplest solution is to use a subshell to do your work.

eg

$ bash
$ x=100
$ echo $x
100
$ exit
$ echo $x

$

All the variables you set between running bash and exiting that shell will be forgotten.

This is very close to how the wget ... | bash part works as well, except you can cut'n'paste/type commands.

1

Actually the simplest way might be to just use a compound command with a variable declaration at the start.

If you declare a variable at the start of a command line, the variable is temporarily defined only for the scope of that command.

madumlao@lezard:~$ x=foo
madumlao@lezard:~$ x=y bash -c 'echo $x'
y
madumlao@lezard:~$ echo $x
foo

As you can see, the line with a variable declaration only sets the variable in the environment for that line only.

Note that the following will not work:

madumlao@lezard:~$ x=foo
madumlao@lezard:~$ x=y echo $x

madumlao@lezard:~$ echo $x
foo

The $x in the second line is parsed during command-line parsing, before the value is actually assigned, so it is unexpectedly blank!

You must log in to answer this question.