-1

Consider the following example:

file="test" echo $file

My idea is that file persists only during the command echo $file. Although $file does not persist after this command, echo prints nothing, as if $file were not set.

Is it possible to set one-command-lifelong variables in the shell?

edit: I don't want to resort to shell scripts or functions as suggested in all these related questions

9
  • Relating (duplicate?): unix.stackexchange.com/q/628231/117549
    – Jeff Schaller
    Commented Feb 2 at 15:49
  • @JeffSchaller It is related but not duplicated, at all. He/She looks for persistent variable assignment during command execution. I look for nonpersistent variable assignment during command execution. Commented Feb 2 at 16:09
  • 2
    The linked Q&A does explain what’s happening in your test: file is set only for echo, but $file is expanded before echo runs (it has to be) so $file is empty when it’s expanded. Try the example given in the linked answer, using a shell script: you’ll see that the variable is indeed set for the command (in a non-persistent manner). Commented Feb 2 at 16:18
  • 1
  • 1
    The thing is, your command here, file="test" echo $file does exactly what you want it to do. Can you edit and clarify the use case? Do you really want the variable to only be available in the command's environment, or do you want it to be available in the parent (which is what echo "$var" requires) but to then be unset after the command finishes? If you only want it to exist in the command's environment, "for the lifetime of the command" then var=foo command is the right way.
    – terdon
    Commented Feb 2 at 16:57

2 Answers 2

1

The variable binding in your command line doesn't take place until the command line is executed. But the parameter substitution of $file takes place while the command is expanded, which must happen before it is executed.

The way around this is to put your command into a function:

fun()
{
   echo "file = " $file
}

file=abc fun
2
  • Note that when prefixing functions with var=value, POSIX leaves it unspecified whether or not the variable assignments persist after the completion of the function. In practice, it doesn't in ksh. Commented Feb 3 at 7:40
  • @StéphaneChazelas Works as an override in Bash and Zsh also; work as a dumb assignment in Dash.
    – Kaz
    Commented Feb 3 at 22:55
1

The command

file="test" echo $file

doesn't output test because the expansion occurs before running the command. Check this out:

$ set -x
$ foo='hello' echo $foo
+ foo=hello
+ echo

The same thing doesn't occur when you run a Unix shell script instead of running a shell command, e.g.,

foo='hello' /path/to/script.sh

In this case, the foo='hello' assignment is first resolved, then /path/to/script.sh is run.

Some previous and related posts proposed solutions for persistent variable assignment + CLI commands:

  1. foo='hello' bash -c 'echo $foo': Using shell script is not desirable! Wordy approach to simple commands.
  2. (){ local var=value; echo "1: $var"; }; echo "2: $var": Using functions is not desirable! Wordy approach to simple commands.
  3. TEST=foo && echo $TEST: Simple but persistent.

My way out is

(file="test"; echo $file)

By creating a subshell, you can create a shell variable, use it in the echo command, and then it won't persist outside this command.

9
  • Can you explain why you consider examples 1 and 2 as creating “persistent” variables? If foo is initially unset, after foo=hello bash -c 'echo $foo' it remains unset. Commented Feb 2 at 16:33
  • @StephenKitt I edited to make clearer which solutions make persistent environment variables. Commented Feb 2 at 16:37
  • 1
    I don't understand this. var=value command is exactly what you want: it sets the variable var to value only for the execution environment of command. Your solution here actually does make it persist outside, it's just that you are adding the extra step of running a subshell and the variable is set only in the subshell. So once the subshell exits, you no longer have the variable set, but that isn't what your question asked for.
    – terdon
    Commented Feb 2 at 16:55
  • file='test' eval 'echo $test' has the advantage that it does not create an extra shell.
    – NickD
    Commented Feb 2 at 17:06
  • 1
    @terdon, well, in e.g. (foo=xyz; echo "$foo"); echo "$foo" the modified value of foo effectively persists only for the duration of the first echo (including the expansions in that command), not the rest of the script (the second echo), so IMO, it looks to fill their desire exactly. Too bad something like foo=xyz { whatever... } doesn't work.
    – ilkkachu
    Commented Feb 2 at 18:29

Not the answer you're looking for? Browse other questions tagged .