Search code examples
bashls

A bash function definition that doesn't seem to work


I was experimenting with shell functions the other day, with the objective of overriding the ls command. The intention was to have the shell call my ls function first then if the first switch is "-y" do one thing, otherwise call the regular /bin/ls, but the result behaves in a way I don't understand.

To enable it I decided to use "-y" for the switch because:

$ ls -y
ls: invalid option -- 'y'
Try `ls --help' for more information.

So it can't break the core functionality of ls. Anyway, reducing the problem to its simplest, and with a couple of other examples to help highlight the problem:

$ function ls() { [[ "y$1" == "y-y" ]] && echo LS ; } 
$ function less() { [[ "y$1" == "y-y" ]] && echo LESS ; }
$ function try() { [[ "y$1" == "y-y" ]] && echo TRY ; }

So I'm overriding ls, less and defining try which is like the "contol" specimen :)

Now Invoking this way:

$ ls ; less ; try 

It behaves as expected (no output), but:

$ ls -y ; less -y ; try -y
LESS
TRY

the ls fails to work, but the less override does, as does the "control".

Elsewhere on stackoverflow or askubuntu (but I've lost the reference for the minute) I saw an example that implied ls was a builltin, but:

$ which ls
/bin/ls

and:

$ builtin ls
bash: builtin: ls: not a shell builtin

So it doesn't seem to be on my system (and even if it was I can't actually see why it would behave like this).

I wonder what the explanation is? It isn't important, but I'd like to understand what's going on.

Thanks.


Solution

  • Don't use which, use type. If you have something like

    $ type ls
    ls is aliased to `ls --color=auto'
    

    Then your function will fail in an interactive shell. Remove this in your .bashrc or wherever its defined. You can also use the unalias builtin.

    You also need to avoid recursion if running a command of the same name as a function within a function.

    ls()
        if [[ $1 == -y ]]; then
            shift
            ...
        else
            command ls "$@"
        fi
    

    Also, make sure you know what you're doing if you decide to define functions using the function keyword. Use POSIX-style funcname() compound-command when you need POSIX compatibility as of this writing.