1

As part of my workflow, I tend to ll (alias ll='ls -l') into a directory to see if the files I need are there, and after that, I cd into the same dir to do whatever I had to do.

I would like to add an alias (or bash function) that would allow me to have the same functionality as !! or sudo !!. Namely, if I type ll /mnt/Disc1/somedir, and find the files that I want to work on in that directory, I would like to be able to just type cd !! (or something similar) so that if I run the hypothetical cd !! alias, this would change the ll from the previous command to cd while keeping the absolut/relative path, and the run the command with se substitution, so that now I am on /mnt/Disc1/somedir instead of the dir where I was previously.

Following this answer, I managed to get a working version:

cd "$(echo !-1 | awk '{print $2}')"

If I run this on the terminal it does exactly what I want (echo !-1 prints the last command from history, namely ll /mnt/Disc1/somedir and after piping this to awk '{print $2}' it prints the 2nd column, namely /mnt/Disc1/somedir, so this becomes the argument/parameter for the cd command).

My problem is defining an alias for this command.

Functions

Most of the answers I have come across suggest using functions as a solution (here for example), while this answer, after the function part, suggests using literal quotes. For a moment I thought that this would solve my problem but I can't get it to work. The main problem I have with functions is that I can't seem to find a way to make the !-1 part work with out me having to explicitly type the path as an argument for the function.

Quote Escaping

From what I have read (mainly this and this), I believe that if I could understand the proper way to escape the quotes, then I should be able to have a working version of the alias that I want. The problem with the answers I have found is that they don't explain the proper way to escape quotes (or special symbols) nor point to a good reference to learn how to do it (like this one that gives many examples but not enough explanation for me to learn the proper way to do it). They just work for the case at hand or give examples that I have been unable to adapt to my case.

As an alternative, I tried to use the cut command (instead of awk) to try to bypass the need for the single quotes around the {print $2} part. But as you can imagine, to define a different delimiter I had to use quotes...

Edit As pointed out in this answer, I was trying to solve this the wrong way. See @frabjous comment for a working solution.

6
  • Heck you can just use $_ for the last argument to the previous command. alias mycd='cd $_' would do the trick, I think.
    – frabjous
    Commented Jun 5, 2022 at 0:48
  • @frabjous Thank you! You just made the amount of time I have "wasted" the past couple of days trying to solve this worth it. Your suggestion actually does what I expect. Consider putting your comment as an answer because, lacking a more adequate answer, I would gladly accept yours. Cheers!
    – Jesus DA
    Commented Jun 5, 2022 at 1:39
  • That's tempting, but even though your particular use case can be solved a different way, you still raise an excellent question: is it possible to use history expansion with exclamation points in an alias, and if so, how? I don't know the answer to that question. Maybe consider editing the question to make it about that, because that's a good question!
    – frabjous
    Commented Jun 5, 2022 at 1:43
  • I think it is. Anyway, thank you for the help and I will consider narrowing the scope of the question.
    – Jesus DA
    Commented Jun 5, 2022 at 1:49
  • History expansion takes place before alias expansion, so no, you'll have to resort to trickery
    – muru
    Commented Jun 5, 2022 at 2:06

1 Answer 1

2

A companion to !! is !$ -- the last argument of the previous command.

ll /some/dir
cd !$

See 9.3 History Expansion in the manual


Using this in an alias: the linked manual section says

History expansion is performed immediately after a complete line is read, before the shell breaks it into words

Aliases are substituted after that, as described in 3.1.1 Shell Operation

  1. Breaks the input into words and operators, obeying the quoting rules described in Quoting. These tokens are separated by metacharacters. Alias expansion is performed by this step (see Aliases).

Given the above statements, I don't know if it's even possible to have history expansion occur in an alias. Functions can give you all the flexibility you want:

lcd() {
    local ans
    ll "$1"
    read -rp "cd there? [Y/n] " ans
    if [[ ${ans,,} != n* ]]; then
        cd "$1"
    fi
}

Adjust the UI of that function to suite your taste.

2
  • But is it possible to use !$ in an alias? If you use double quotes, it'll expand when defining the alias, which is no good. If you use single quotes, it doesn't expand even when used. That's the gist of OP's question, I think. This is why I suggested $_ (in single quotes) instead in the comments.
    – frabjous
    Commented Jun 5, 2022 at 1:17
  • As commented by @frabjous, I am no closer to understanding the right way to escape quotes on bash. Also, this works like a charm as long as I don't use it as an alias because I get -bash: cd: !$: No such file or directory.
    – Jesus DA
    Commented Jun 5, 2022 at 1:34

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