4

When I attempt to tab complete a filename in the bash prompt, and the output would be many (>100) filenames, the shell asks Display all <num> possibilities? (y or n)

Can I replicate this behaviour with the normal ls command?

I have a directory with >400k files. Accidentally lsing this directory leaves me with an unresponsive shell for many minutes while it spews output. Ctrl-C doesn't stop the flood.

2

My solution might be a little heavy but well, who knows.

The problem is that, in order to do that, you would need to count files... which is usually done with:

$ ls | wc -l

Now, because the content is written to a pipe, and not to stdout, this will take a little less time to complete (writing to a terminal takes a little bit of time, which can become significant with 400k calls to write(2)). It might still take some time, but nevertheless, you could implement this with a simple test:

#!/bin/bash

LIMIT=1000
n=$(ls "$@" 2>/dev/null | head -n$LIMIT | wc -l)

if [ $n -ge $LIMIT ]; then
    echo "This directory contains more than $LIMIT entries."
    echo -n "Are you sure want to continue? (y/N) "

    read confirm
    if [ "$confirm" = "y" -o "$confirm" = "Y" ]; then
        exec ls "$@"
    fi
else
    exec ls "$@"
fi

Then, just set an alias in your .bashrc file, to call this script instead of /bin/ls:

alias ls='/path/to/my_ls.sh --color=auto'

Also make sure it is properly chmoded:

$ chmod +x /path/to/my_ls.sh

Edit: I added a call to head so that ls is terminated after $LIMIT lines of output. This should save some time (and actually make it a better solution that the timeout one) ;)

Another approach I would suggest is to use a timeout. If ls doesn't complete in say 5s, it should stop and ask you if you're sure about it. Here's a example script (valid for several commands, not just ls) :

#!/bin/bash                                                                                                                                                                                

TIMEOUT=5

if [ $# -le 0 ]; then
    echo "Usage: $0 [command]"
    exit 1
fi

# Try it silently for a few seconds...
timeout $TIMEOUT "$@" >/dev/null 2>&1

if [ $? -eq 124 ]; then
    echo -n "Your command failed to run under "$TIMEOUT"s. "
    echo -n "Retry without a timeout? (y/N) "

    read confirm
    if [ "$confirm" = "y" -o "$confirm" = "Y" ]; then
        exec "$@"
    fi
else
    exec "$@"
fi

Then you could set a few aliases, such as:

alias ls='/path/to/script.sh ls --color=auto'
alias grep='/path/to/script.sh grep --color=auto'
alias cat='/path/to/script.sh cat'

Note that I'm testing $? -eq 124 because...

If the command times out, and --preserve-status is not set, then exit with status 124.

See timeout(1) for more information.

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.