zibi
zibi

Reputation: 3313

Create alias using bash one liner

I need to create alias for my long command, normally I would use

alias myLongCommand="my long command"

but I need to define in an online system configuration where I can only use bash command, I tried various combinations including:

bash -c 'alias myLongCommand="my long command"'

but unfortunately with no success, alias does not get defined.

To test success I use

bash -c myLongCommand

Upvotes: 2

Views: 2920

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295272

Short answer: Use an exported function instead

# define a function
myLongCommand() { my long command; }

# export that function to the environment
export -f myLongCommand

# thereafter, that function is available in subprocesses
bash -c 'myLongCommand'

...or, to compress the actual creation into a one-liner:

myLongCommand() { my long command; }; export -f myLongCommand

Note that the definition and export needs to be done in a bash shell that is itself a parent process of the shell in which you intend the function to be used. If you use bash -c 'myLongCommand() { my long command; }; export -f myLongCommand', then the environment variable with the exported function lives only as long as that bash -c instance does -- hence, it's entirely unavailable in any subsequent command.

If you wanted this to be available for all bash shells in your login session, you could put the definition and export in ~/.bash_profile (and log out and back in), if your system is behaving per typical defaults with respect to dotfile initialization.

Longer answer: Why did the original attempt fail?

Multiple reasons:

  • Aliases are part of the state of an individual shell process -- there isn't a shared registry. Thus, bash -c 'alias foo="bar"' sets up an alias only for that single bash instance created by the bash -c command, and that alias is terminated when that command exits.
  • Noninteractive shells, such as those created with bash -c, don't inherit aliases from their parent processes, or read dotfiles (by default), so they start out with their alias table empty, even if an alias is defined in the (separate) shell that's invoking them.
  • Noninteractive shells, such as those created with bash -c, have alias evaluation turned off by default, as this is intended to be an interactive-use feature.

Longer answer: Why not an alias?

Aliases are intended as a facility for interactive use. Thus, they're not by default available inside noninteractive shells at all. To enable alias expansion in a noninteractive instance of bash, one needs to run:

shopt -s expand_aliases

The other issue is actually getting that alias defined at all. Noninteractive shells don't run dotfiles by default (the name of a dotfile to run in a noninteractive shell can be placed in the ENV or BASH_ENV environment variable to override this), so they won't have aliases defined in ~/.bashrc present.

Longer answer: ...so, how could you use an alias?

# create a .env file, taking care not to fail badly if shell is not bash
# note that making noninteractive shells emit content on stderr will break some software
# ...so redirecting errors is entirely essential here, and ||: is necessary to not break
# ...any noninteractive shell (like dash or ash invocations) that doesn't support shopt
# ...when that shell is invoked with the -e argument.
cat >~/.env <<'EOF'
shopt -s expand_aliases 2>/dev/null ||: "fail gracefully w/o shopt"
alias myLongCommand="my long command" 2>/dev/null ||: "fail gracefully w/o aliases"
EOF

# point to it from your .bash_profile
cat >>~/.bash_profile <<'EOF'
export ENV=$HOME/.env
[[ -e $ENV ]] && source "$ENV"
EOF

# ...and update the already-running shell:
export ENV=$HOME/.env
source "$ENV"

...to do the above in one line:

printf '%s\n' 'shopt -s expand_aliases 2>/dev/null ||:' 'alias myLongCommand="my long command" 2>/dev/null ||:' >~/.env; printf '%s\n' 'export ENV=$HOME/.env' '[[ -e $ENV ]] && source "$ENV"' >>~/.bash_profile

Upvotes: 5

heemayl
heemayl

Reputation: 41987

bash -c spaws a non-login, non-interactive instance of bash, which does not read any session startup configuration file (unlike login/interactive sessions), hence no alias definition available and also only exits when the command (alias myLongCommand="my long command" in this case) exits. So presumably you won't get the alias available.

To permanently set aliases, you should use any file that shell reads when starting the session, for interactive session, bash reads ~/.bashrc. So if you put your alias definition there, it will available on any interactive bash instance:

echo 'alias myLongCommand="my long command"' >> ~/.bashrc

To make it avail;able from the running session , source the file:

source ~/.bashrc

Now from an non-interactive (and non-login) session i.e. bash -c you can make this alias available by making the shell interactive too using the -i option, so the ~/.bashrc is read:

bash -ic 'myLongCommand'

Upvotes: 2

Related Questions