11

How to reuse the apt up part of the apt update and apt upgrade commands to execute both commands in sequence in just one line without an alias.

Something like: apt up{date,grade}.

3
  • What would actually be the aim of achieving this? Why may this be interesting/relevant? – vanadium Oct 22 '18 at 13:08
  • 25
    @vanadium we are linux users, trying pointless things allows us to learn techniques that can be applied later to more complex things, if none of us ever did that let's be honest none of us would be here – Darren H Oct 22 '18 at 13:18
  • 1
    @DarrenH That is what I thought indeed :-) – vanadium Oct 22 '18 at 13:19
19

The simple way ( and more efficient) is via for loop (on one line but here it's shown in multiple lines for clarity):

for i in {date,grade}; do
     apt up${i}
done

The smart way is to make an alias in ~/.bashrc for these two commands and forget about retyping it ever again:

alias upgrade=' sudo apt update && sudo apt upgrade'

The elaborate way is to do this:

$ echo sudo" "apt" "up{"date","grade"}" && " :
sudo apt update &&  sudo apt upgrade &&  :

See what's happening ? We're building a valid string of text to be run by shell. Now all you need to do is to use eval instead of echo. But eval is generally not recommended in shell scripting and this command is much more convoluted and non portable than the for loop. Variation on the theme without eval (and shortest so far, but not efficient due to pipe and multiple commands echo,two apt,sudo and sh so lots of forking):

$ echo "apt "{update,upgrade}";"|sudo sh

We can also use set to turn the desired sequence into positional parameters and just execute apt with $1 and $2 args:

$ set {update,upgrade}; echo apt $1 && echo apt $2
apt update
apt upgrade

Or alternatively use for loop again, since it defaults to processing positional parameters if you don't specify a sequence in the for variable (sequence)

$ set {update,upgrade} ; for i; do echo apt $i ;done
apt update
apt upgrade

Using set is a very common technique I see among professionals who work with shells a lot, and for a good reason - this is very portable and will work in /bin/sh where you have no arrays or {a,b,c} expansion. So POSIX-ly portable way would be set update upgrade ; for i; do echo apt $i ;done. Additionally, this should be efficient.


Or we can go the while loop route:

$ echo {date,$'\n',grade}|while read i;do echo apt up${i}; done 
apt update
apt upgrade

Of course remember to run it without echo for actual command execution to take place

14
  • 7
    Just do the for loop in one line. for i in {date,grade}; do sudo apt up${i}; done – Videonauth Oct 22 '18 at 7:15
  • 3
    If you prefer to keep your files nice and tidy, you can put aliases in ~/.bash_aliases, too. This file should be automatically sourced by ~/.bashrc. – francescop21 Oct 22 '18 at 7:36
  • 2
    I've updated my answer with perhaps what you want. It is a one-liner, but I don't think if it makes it any easier. Frankly, there's no point in doing this when you want to run two commands (yes, that's two apt commands) with different arguments (update and upgrade), so I'll still say for loop is the way to go – Sergiy Kolodyazhnyy Oct 22 '18 at 7:38
  • 1
    No need for string expansion in for loop header, just name the iterations: for i in date grade; do – rexkogitans Oct 22 '18 at 9:23
  • 5
    Such an alias should obviously be named upgrate. – pipe Oct 22 '18 at 11:01
14

You can also use bash history expansion to get parts of the current command line and modify it:

$ apt update; !#:s/date/grade
apt update; apt upgrade;
Reading package lists... Done
...
  • !# is the current line
  • :s/date/grade is a modifier that substitutes date with grade
1
  • 6
    You can even save 2 more characters by using !#:s/dat/grad instead – Dan Oct 22 '18 at 22:46
9

Another simple option using xargs instead of for:

echo up{dat,grad}e | xargs -n1 apt

Test:

$ echo up{dat,grad}e | xargs -n1 echo apt
apt update
apt upgrade

However, I’d prefer a shell alias just like Sergiy because these “simple” ways are not simple enough to be actually useful.

3
  • 1
    Very nice. Variation on the theme could be printf "%s\n" {date,grade} | xargs -I% -n1 echo apt up% although this is a bit longer – Sergiy Kolodyazhnyy Oct 22 '18 at 7:44
  • printf '%s' is generally good practice since you can't escape it, e.g. with --help or -e. – yyny Oct 22 '18 at 9:35
  • @YoYoYonnY Yes. Maybe printf '%s\0' would be even better, xargs has a flag to handle null terminated args – Sergiy Kolodyazhnyy Oct 22 '18 at 10:08
2

Create a function like this:

repeat() { 
    for suffix in "${@:2}";
    do
        eval "$1""$suffix";
    done
}

Then you can run repeat 'apt up' {date,grade}. This has the benefit of being reusable for totally different commands, although it's not saving you any typing for this one.

I'd certainly agree with some of the other answers that something like this is probably more useful:

alias apt-up='apt update && apt upgrade'
0

@muru's answer led me to read up on history expansion and I found another variant

 $ sudo apt update
 $ ^dat^grad^

^string1^string2^ is equivalent to !!:s/string1/string2/, which takes the last command and replaces string1 with string2.

-2

I resuse the apt-get up part of the command using the following key sequence:

Up ArrowBackspaceBackspaceBackspaceBackspace

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.