2

I made an alias alias goto="cd $@ && source ~/.zshrc" and it works, but only if I execute it twice. Even after I execute it twice in one shell, and if I want to move to another dir, I must again execute it twice. Why is that and how can I change that?

I need to type two times goto <dir>. The first time, I am still in the normal dir and the second time, I got to my destination. I need to source .zshrc, because I have a check for the path:

CURRENT=$PWD
AT_HOME=0
AT_ROOT=0

if [ $PWD = $HOME ]; then
    AT_HOME=1
elif [ $PWD = / ]; then
    AT_ROOT=1
else
    cd ../

    if [ $PWD = $HOME ]; then
        AT_HOME=1
    elif [ $PWD = / ]; then
        AT_ROOT=1
    else
        cd ../

        if [ $PWD = $HOME ]; then
            AT_HOME=1
        elif [ $PWD = / ]; then
            AT_ROOT=1
        fi
    fi
fi

cd $CURRENT

if [ $AT_HOME = 0 ]; then
    if [ $AT_ROOT = 0 ]; then
        ZSH_THEME="prompt-basename"
    else
        ZSH_THEME="prompt-normal"
    fi
else
    ZSH_THEME="prompt-normal"
fi

And it gives me full path (even at /usr/lib/jvm/java-13/bin) and when I source ~/.zshrc, it gives me the path I want (.../java-13/bin). By the way, replacing && with ; does not work neither.

Thanks!

*This is my first Question at stackxchange.com, so please don't be too rough.

Leo1807
  • 23
  • 5
  • What is in `~/.zshrc`? Something in there might be tripping up zsh's alias system? Maybe if you edit your question to state what you are trying to do with the alias, someone who knows a cleaner and efficient way to do so will contribute an answer? – C. M. May 14 '21 at 01:12
  • 1
    It would be interesting to know the definition of "it works". What is the outcome when it does not work? Also, what do you have to enter twice - `goto` or the `alias` command? While I can assume the most likely answers to these questions, it's better that you clarify them. – berndbausch May 14 '21 at 01:25
  • 6
    Aliases don't use arguments, the `$@` isn't what you think it is there. – muru May 14 '21 at 01:53
  • Does it work when you use `;` instead of `&&`? If so, then `cd`'s exit status is not 0, which means it failed. – glibg10b May 14 '21 at 05:47

2 Answers2

4

First of all, aliases are not functions and do not accept arguments. Rather, aliases are simple substitutions: When you type goto foo on the command line and press Enter, the shell simply replaces goto with the value of the alias, before executing the command line.

Therefore, $@ does not expand to the arguments passed to your alias. In fact, in this case, it expands to the arguments passed to shell or the script you're sourcing. This is why goto works correctly the second time: You have now passed a directory as an argument when sourcing your .zshrc file and $@ will expand to that argument when you declare the alias again.

Additionally, since you're using "double quotes", $@ expands immediately when you declare the alias. To see that this is the case, right after your shell has started up, type alias without arguments to view your aliases.

If you want goto to be able to handle arguments, you should declare it as a function: goto() { cd $@ && ... }

However, as a rule, ⚠️you should not source ~/.zshrc. Depending on what's in your dotfiles, this can lead to all sorts of problems.

Instead, if you've made changes to your .zshrc file and you want to apply them, you should either restart your terminal (by closing the current tab/window and opening a new one) or restart the shell (by typing exec $SHELL).

Marlon Richert
  • 3,715
  • 5
  • 30
  • The quotes will explain why OP has to "run it twice for it to work". The first time, the directory is an argument to `~/.zshrc` as it gets sourced, so when the alias gets redefined during that, the `$@` in the alias expands to the directory. So the second time the alias does have `cd `, and it works. – muru May 14 '21 at 07:51
  • Thanks. I've updated my answer. – Marlon Richert May 14 '21 at 08:08
  • Why should you not source `~/.zshrc`? Opening a new terminal will source it anyway, so why would there be an issue if you source it manually? – terdon May 14 '21 at 09:32
  • @terdon Because it's been sourced already when your shell started up and the order in which commands are run can matter. As a simple example, put `ls() { command ls "$@" | less }; alias ls='ls -AF'` into your `.zshrc` file, restart your shell, then `source ~/.zshrc`. Now you get an error `zsh: defining function based on alias 'ls'`. And that's only a fairly innocuous example. Things can get much more hairy than that, especially when your `.zshrc` in turn sources 3rd-party files. – Marlon Richert May 14 '21 at 09:39
  • That doesn't actually give me an error in zsh. But even if you can find some edge case that does, I am surprised you seem so adamant against this. I have been changing my `~/.bashrc` and then sourcing it for many years and have never once encountered a problem. Maybe I have been lucky, but it seems more likely that what you are describing isn't a very common problem. Or perhaps it is special to zsh? Come teach me here: [Is there any reason to avoid sourcing the shell's configuration file?](https://unix.stackexchange.com/q/649665) – terdon May 14 '21 at 09:55
  • @terdon Read this answer for a more in-depth explanation: https://unix.stackexchange.com/a/532591/413610 – Marlon Richert May 14 '21 at 12:26
  • Actually, all the answers on that question are good. – Marlon Richert May 14 '21 at 12:29
  • In particular, this line sticks out to me as always being a problem when doing `source ~/.zshrc`, no matter what you do in there: 'Moreover, if there were deleted lines from the old .zshrc, then they wouldn't be "erased" from the session.' – Marlon Richert May 14 '21 at 12:32
0

Marlon's answer works. Instead of making an alias, I did following function:

function goto {
    cd $@ && exec $SHELL
}

And it works perfectly. I also remarked, that sourcing ~/.zshrc takes longer and longer after every call of goto.

Leo1807
  • 23
  • 5