25

I want to make an alias for a multiline ​command to call it faster then copying-pasting-executing it from a text file each time.

An example for such command is this execute-a-remote-updater command:

(
cd "${program_to_update_dir}"
wget https://raw.githubusercontent.com/USER/PROJECT/BRANCH/update.sh
source update.sh
rm update.sh
)

A couple of years ago I have learned that multiline commands' aliases are impossible due to Bash design limitations but perhaps since then the program has been changed and now it is possible.


I think that if it is still impossible, perhaps I could make a function with that code, export it to all shell sessions (although I rarely work with any subsessions and I don't even recall when I last did that), and then call it somehow.

Should it be enough and secure to just wrap it in an exported and named function in say .bashrc or .bash_profile and then call it whenever I need to?

1
  • I would suggest that you won't find any difference in speed between writing a bash script, stored in a file in your $PATH and calling that vs writing those lines in an alias and calling that. Bonus 1: your script will be so much easier to comment and maintain. Bonus 2: your .bashrc will be so much easier to maintain. Aliases have their uses, but for anything above a certain very minimal complication level, I would use a script.
    – jrw32982
    Commented Mar 31, 2021 at 23:51

1 Answer 1

35

It's not impossible at all.

alias thing='(
cd "${program_to_update_dir}"
wget "https://raw.githubusercontent.com/USER/PROJECT/BRANCH/update.sh"
source update.sh
rm update.sh
)'

or,

alias thing='( cd "${program_to_update_dir}"; wget "https://raw.githubusercontent.com/USER/PROJECT/BRANCH/update.sh"; source update.sh; rm update.sh )'

The thing with aliases is that quoting may be tricky to get right as they are text strings, and that they are better suited for really short things, like

alias ls='ls -F'

In almost every other instance, you want a shell function instead:

thing () (
    cd "${program_to_update_dir}"
    wget 'https://raw.githubusercontent.com/USER/PROJECT/BRANCH/update.sh'
    source update.sh
    rm update.sh
)

Or, corrected to not use the update.sh name in the current directory (it may be taken by an unrelated file) and to only run wget if the cd succeeded, and slightly streamlined for the bash shell,

thing () (
    cd "$program_to_update_dir" &&
    source <( wget --quiet -O - 'https://raw.githubusercontent.com/USER/PROJECT/BRANCH/update.sh' )
)

(Note that you may want to run the update.sh script using bash instead of sourcing it, or pipe it to bash -s, or use whatever interpreter its #!-line uses. The fact that you're using source on it is confusing as you're also running it in a subshell. The effect on the environment of running the script with source, which is usually why one wants to source a script, is lost when the subshell terminates.)

Shell functions may be define in the same initialization file that you define aliases in, and they are used in the same way as aliases, but are more versatile (can take arguments etc.)

The bash manual contains the statement

For almost every purpose, aliases are superseded by shell functions.

6
  • Hello ! I understand your point that it's not impossible at all (as a one long line with field separations), but what if one wants to put several line between the double quote marks? Then, as far as I can recall it is impossible. About corrected --- I personally don't like the sugar syntax you have used, I personally find it confusing --- I never had trouble with the syntax I used...
    – timesharer
    Commented Mar 26, 2021 at 9:00
  • 1
    My impression is in most cases like this an asker is not aware that any alias in Bash works by replacing some string with some string. There is no logic, just simple text replacement. Realizing this helped me a lot in understanding the concept. Commented Mar 26, 2021 at 9:02
  • @timesharer See updated answer (the start of it). Also note that your code potentially overwrites a file called update.sh in the current directory, and that it runs the update.sh script regardless of whether the cd was successful, possibly leading to data loss.
    – Kusalananda
    Commented Mar 26, 2021 at 9:10
  • Yes, nice, I should read it carefully again. Thanks,
    – timesharer
    Commented Mar 26, 2021 at 9:36
  • 1
    @timesharer You could probably use wget -O - 'URL' | bash -s, depending on what that update.sh script does (would not work if it's interactive). Or, you could use tmpname=$(mktemp); wget -O "$tmpname" 'URL'; bash "$tmpname"; rm -f "$tmpname".
    – Kusalananda
    Commented Mar 26, 2021 at 9:53

You must log in to answer this question.

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