128

If a run the watch command containing an alias, it will not expand the alias. I have tried both with single quote and double quotes, in fact given the following alias:

# alias ll
alias ll='ls -l --color=tty'

The following command will fail

# watch ll
sh: ll: command not found

Shouldn't command line expansion work in this case?

1
  • I thought maybe we could use "watch -x bash -i -c ll" (the "-x" tells watch not to use it's own "sh -c" to execute the given command.) But it successfully runs 'll' once, then backgrounds and stops the process. I don't know why. May 7, 2020 at 17:52

6 Answers 6

193

Aliases are only expanded as the first argument, or after another alias with a trailing space on the end of the command.

From bash's help alias:

A trailing space in VALUE causes the next word to be checked for alias substitution when the alias is expanded.

To do this, try the following:

alias watch='watch '
alias ll='ls -l --color=tty'
watch ll

Bear in mind that some versions of watch strip colours by default, on some versions this can be stopped by using --color or -G.

6
  • 5
    This is absolutely awesome answer! Thanks and +1 of course.
    – ztank1013
    Nov 25, 2011 at 12:47
  • 3
    Thanks... For all this time, I used to 1. type ll, 2. press ctrl+alt+e, 3. then prefix watch. This is a time saver.
    – anishsane
    May 10, 2016 at 8:02
  • 34
    Unfortunately this method has a limitation that you cannot provide options to watch because the alias has to be the next word, whereas watch needs its arguments before the command to run. If you tried watch -n 10 <alias>, bash won't expand the alias. To work around it, you need an alias that includes the options you want (e.g., `alias watch-10='watch -n 10 '), still with a trailing space.
    – indiv
    Jul 10, 2017 at 19:46
  • 1
    Is there a similar approach to do bash function expansion in a similar manner?
    – Olshansky
    Sep 16, 2020 at 19:38
  • > A trailing space in VALUE causes the next word to be checked for alias substitution when the alias is ----- That abit confusing. It works also in other shells, but dont get the reason.
    – micrub
    Dec 16, 2022 at 23:33
16

Maybe we could manually expand the alias before watch sees it?

watch $(alias ll | cut -d\' -f2)

Explanation

The output of alias ll looks like:

$ alias ll
alias ll='ls -lAGh'

So we set cut's delimeter to be single quote, and cut the 2nd field, leaving:

ls -lAGh

ie the expanded alias. That then forms the args given to watch.

Make a function to do it

function watcha {
    watch $(alias "$@" | cut -d\' -f2)
}

Then,

watcha ll

works as desired. This is awful and will fail in all sorts of situations. Sorry.

3
  • 3
    +1 for enginuity and admintting to the failure cases :)
    – Oliver
    Jun 5, 2020 at 14:29
  • 1
    These answers will fail if the alias has any apostrophes (single quotes) in it. The watcha function will blow up if you try to pass arguments. May 25, 2022 at 6:58
  • 1
    Also it fails if your alias is a function... Nice try though... UpVote
    – Enissay
    Aug 23, 2022 at 23:05
4

Another trick that I use (specifically for aliasing kubectl to k) is to create a symlink instead of an alias. That way the symlink still is found by watch and no trickery is required.

The downside of this is that you have to do this for every alias you want to work, and I'm not sure how it'd work for shell builtins.

1
  • In addition to shell builtins, this would also not work for binaries that check what name they have been called with. This includes busybox, [rustup shims that allow +stable and per-directory overrides], and bash, that disables some features if called as /something/sh Jul 27 at 9:36
1

There's a custom program to handle this over at github.com/antonmedv/watch. It supports multiple shells. Of course because it's custom software to install it's OK for your normal computers but not helpful on random servers you might be connected to. Here's how I run it so I can watch my zsh aliases and functions:

function watch-zsh() {
  WATCH_COMMAND='zsh -ci' /usr/local/bin/watch "$@"
}
1

Here's one that uses the --color option and allows you to use the -n argument to specify a refresh interval.

swatch_usage() {
    cat <<EOF >&2
NAME
       swatch - execute a program periodically with "watch". Supports aliases.

SYNOPSIS
       swatch [options] command

OPTIONS
       -n, --interval seconds (default: 1)
              Specify update interval.  The command will not allow quicker than
              0.1 second interval.
EOF
}

swatch() {
    if [ $# -eq 0 ]; then
        swatch_usage
        return 1
    fi
    seconds=1

    case "$1" in
    -n)
        seconds="$2"
        args=${*:3}
        ;;
    -h)
        swatch_usage
        return 1
        ;;
    *)
        seconds=1
        args=${*:1}
        ;;

    esac

    watch --color -n "$seconds" --exec bash -ic "$args || true"
}

I only needed color and timing support, but I'm sure you could add more if you wanted.

The meat of the function is that it executes your command with bash directly in interactive mode and can thus use any aliases or commands that are normally available to you in bash.

I'm not that experienced with scripting so fair warning, your mileage may vary. Sometimes I have to press Ctrl+C a few times to get it to stop, but for what it's worth, I've been using it frequently for 6 months without issue.

Gist form: https://gist.github.com/ablacklama/550420c597f9599cf804d57dd6aad131

2
  • (1) It seems to me that your usage message is not very clear.  (2) The return statement in the swatch_usage function serves no purpose.  (3) If you run swatch -h, it displays the usage message and then runs watch on a null command.  (4) In the final command line, $seconds should be "$seconds". (5) Naturally, this will stumble if the command has special characters in it. May 25, 2022 at 6:03
  • Thanks for the feedback, i updated it.
    – Dwarf
    May 25, 2022 at 19:47
0

I thought here basic problem is while executing watch, the argument is given to "sh -c" which means if alias ll is not defined in sh(dash shell's) environment then it will not expand it. But I was wrong and this is not the case, Chris' answer above is right.

4
  • 2
    Not exactly. Try watch 'alias ll="ls -l --color=tty"; type ll; ll'.
    – Chris Down
    Nov 25, 2011 at 12:54
  • +1 for immediate response to verify it. I was wrong above. Nov 25, 2011 at 12:58
  • @ChrisDown, so even if watch uses "sh -c" the your explanation is applicable for sh too. Am I right? Nov 25, 2011 at 13:02
  • 1
    That depends on what shell is being used as sh. Notice that this does work: sh -c $'alias ll="ls -l --color=tty"\ntype ll\nll'
    – Chris Down
    Nov 25, 2011 at 13:10

You must log in to answer this question.

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