17

I want to customize the functionality of cd command as per my needs.

I defined the following function - function cd () { cd "$@" && pushd "$@"; }

The intent of this function is to automatically push the directory onto the stack so that it saves me the effort to manually type pushd . every time.

However, the above function is an infinitely recursive function, as the call to cd is interpreted to be the function itself and not the cd built-in.

How do I reference the cd built-in in this function?

I know that aliases can be escaped using \. What is the way to escape functions or reference built-ins in a more explicit way?

Note: I do not want to rename my function to anything else.

2
  • 3
    Why not just alias cd=pushd? What do you expect to happen when you cd to something that isn't an absolute path (eg, cd ../)?
    – phemmer
    Nov 27, 2013 at 12:36
  • @Patrick pushd does not support -P. But you are right, as shown in the question the function cd looks a bit wrong, as it changed directory twice.
    – Tino
    May 10, 2019 at 16:21

4 Answers 4

21

Bash has a (builtin) command builtin, which does exactly what you need. Replacing cd with builtin cd in your function will fix the recursion.

10

The command builtin forces a command name to be interpreted as a built-in or external command (skipping alias and function lookup). It is available in all POSIX shells including bash.

cd () { command cd "$@" && pushd "$@"; }

(Note that this example is a bad one: it doesn't work with relative paths, and you might as well just type pushd in the first place.)

In bash and zsh (but not ksh), you can use builtin to force a command name to be interpreted as a builtin, excluding aliases, functions and external commands.

1

I suspect when you say you "don't want to rename your function to anything else," you mean that you want to be able to call your function by the same name as the original command.

So, another way to do this that also works for things that aren't built-ins, is to name your function something else, and then define an alias for the wrapped command. This works because the alias doesn't exist in the execution context of your function.

Example wrapper.sh:

#!/bin/bash
function my_wrapper() { wrapped_program $@ && dostuff }

And in, e.g., .bash_aliases:

source /path/to/wrapper.sh
alias wrapped_program="my_wrapper"

But this is pretty hacky. Using command is preferable when possible.

-1

For this to work with relative paths, the following would be needed:

function cd { 
   dir="$(realpath "$@")"
   command cd "$dir"
   pushd "$dir"
}

This assumes you are on a modern enough Linux distro which contains the 'realpath' utility. (RHEL 6 does not for instance). If Perl is available, 'realpath' can be simulated using:

! realpath $(pwd) > /dev/null 2>&1  && function realpath {
    perl -e "use Cwd realpath; print realpath(\"$1\") . \"\\n\";"
}

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.