3

How do I create an environment variable that is the result of a specific command? Specifically, I want an environment variable ($BWD) that is the basename of $PWD

$ cd /home/devel/Autils/lib
$ echo $PWD
/home/devel/Autils/lib
$ # something here to assign BWD
$ echo $BWD
lib
9

In general the sequence foo="$(bar)" will run the command bar and assign the output to the variable.

e.g.

% echo $PWD
/home/sweh
% BWD="$(basename "$PWD")"
% echo $BWD
sweh

This creates a shell variable. If you want to make it into an environment variable (which can be seen by sub-shells) you can export it.

e.g.

export BWD="$(basename "$PWD")"

However, in this case don't need to run a command, but use shell variable expansion

BWD=${PWD##*/}
  • 1
    The next step would be to automatically update BWD when cd is used: cd () { builtin cd "$@" && BWD=${PWD##*/}; }. – Kusalananda Jan 7 at 20:35
  • @Kusalananda trap 'BWD=${PWD##*/}' DEBUG :-) – Stephen Harris Jan 7 at 20:39
  • Depending on the shell used, yes. – Kusalananda Jan 7 at 20:45
  • I'd add quotes to the echo commands as well. – kasperd Jan 8 at 9:16
12

In Bourne-like shells, you create environment variables by marking a shell variable with the export attribute (so it's exported to the environment of the commands that the shell will execute) by using the export builtin utility:

export BWD

To assign a value to a shell variable, the syntax is:

BWD=value

You can make that value the output of command by using command substitution. In the Bourne shell, that was with the `the-command` syntax, but in modern Bourne-like shells, the preferred way is with $(the-command) instead:

BWD=$(the-command)

Usually, you need quotes around command substitutions to prevent split+glob. However, split+glob doesn't occur in assignments to scalar variables, so they're not necessary here.

The command to get the base name of a file path is the basename command.

basename "$PWD"

(the quotes there are necessary as split+glob does occur in arguments to commands).

That would return the base name of the file stored in $PWD, unless that value starts with -, in which case, YMMV as many basename implementations will treat it as an option. So generally, when passing variable data to command, we use a -- to tell the command that what's after is not to be taken as an option even if it starts with - (here, $PWD should always start with / except in very pathological cases, so it's not strictly needed).

BWD=$(basename -- "$PWD")
export BWD

In modern shells, you can combine both with:

export BWD="$(basename -- "$PWD")"

(the quotes are needed in some implementations as we're back in the arguments of commands, though some other implementations do parse the arguments of export like assignments as a special case under some conditions).

One problem with that approach is if the value of $PWD ends in newline characters (unlikely in practice) as command substitution strips all trailing newline characters. So in:

mkdir $'foo\n\n'
cd $'foo\n\n'
export BWD="$(basename -- "$PWD")"

$BWD will contain foo instead of $'foo\n\n'.

Instead, you may want to use shell builtin operators to get that base name. In zsh, that can be done with $PWD:t (t for tail); in all POSIX-like shells (including zsh), that can be done with ${PWD##*/} which removes everything up to the right-most / from the content of $PWD.

It will give a different result however if $PWD is /. In that case, basename returns / but ${PWD##*/} or $PWD:t expand to the empty string instead. For a directory like /foo/bar/ ($PWD usually doesn't end in / though except for / itself), basename and $PWD:t give bar, while ${PWD##*/} give the empty string again.

For a variable that dynamically expands to the basename of $PWD, you may use ksh93 and its discipline function:

ksh93 also has a builtin version of basename provided you have /opt/ast/bin ahead of $PATH. So in ksh93:

$ PATH=/opt/ast/bin:$PATH
$ type basename
basename is a shell builtin version of /opt/ast/bin/basename
$ BWD.get() { .sh.value=${ basename -- "$PWD"; }; }
$ cd /var/log
$ echo "$BWD"
log
$ cd /usr/local
$ echo "$BWD"
local
$ export BWD
$ printenv BWD
local

Above, we're using a ksh93-specific form of command substitution: ${ the-command; } which is more efficient in that it doesn't create a subshell environment to run the command.

3

You can use the construct foo="$(command)" to return the output of command into the variable foo. So, for your use-case:

$ BWD="$(basename "$PWD")"
  • 2
    Or BWD=${PWD##*/} – jasonwryan Jan 7 at 20:12
  • True, but does not answer the underlying actual question asked (to wit: how to assign the output of a command into a variable). – DopeGhoti Jan 7 at 20:31
  • eh? What do you think BWD is? The fact that OP assumes it requires a command does not make it necessary, just misguided. – jasonwryan Jan 7 at 20:40
  • Again, this specific use-case does in fact not require a command, but the question explicitly asked was "how do I get the output of a command into a variable". – DopeGhoti Jan 7 at 20:51
  • OP also explicitly says: "Specifically, I want an environment variable ($BWD) that is the basename of $PWD" Don't selectively quote just because you assume it supports your argument, that is bad faith. OP wanted an outcome, and like many posters, assumed there was only one route there. – jasonwryan Jan 7 at 20:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.