Bat: "ls" functionality when called with a directory

Created on 2 May 2020  路  3Comments  路  Source: sharkdp/bat

_(I'm sorry if this is a duplicate, I can't imagine it's not, yet I've search a lot and can't find anything)_

It would be wonderful if bat behaved like ls -lh ... when executed with a directory as an arg.

This would be particularly useful when looking for a file to display; currently I often end up replacing bat with ls -lh at the beginning of a long path.

Obviously it would be useful if the output was highlighted unlike normal ls.

The main downside I can imagine would be confusion when "conbatenating" multiple files: if I accidentally included a directory instead of a file as one of the paths, however:

  1. unlike cat I imagine bat is rarely used for this, especially in scripts
  2. bat could continue to use a non-zero exit code when executed with a path to show it's not the primary intended purpose, while still showing the list of files - I'm not advocating this, just a potential work around

If this is something you'd be interested in, I'd be willing to have a crack at a PR, through I a somewhat novice rust developer.

feature-request

Most helpful comment

This is a pretty cool idea, but I think it could also be solved in a few easier ways too:

  1. If we add support for lesspipe, it could probably be configured to ls and highlight any directories passed as an input.

  2. A wrapper script that combines bat and exa. Exa is already a well-established project that provides exactly what you're looking for, and it shouldn't be much harder to implement as a wrapper than adding this to your .bash_profile:

bat() {
    local arg
    local files=()
    local dirs=()

    for arg in "$@"; do
        if [ "${arg:0:1}" = "-" ]; then continue; fi
        if [ -d "$arg" ]; then
            dirs+=("$arg")
        elif [ -e "$arg" ]; then
            files+=("$arg")
        fi
    done

    if [ "${#files[@]}" -gt 0 ] && [ "${#dirs[@]}" -gt 0 ]; then
        printf "\x1B[31m[%s error]: %s\x1B[0m%s\n" "$0" "Cannot concatenate files and directories"
        return 1
    fi

    if [ "${#dirs[@]}" -gt 0 ]; then
        exa "${dirs[@]}"
        return $?
    fi

    bat "$@"
    return $?
}

The main downside I can imagine would be confusion when "conbatenating" multiple files: if I accidentally included a directory instead of a file as one of the paths

I would just consider it an error, to be honest. There's such a low likelihood of it being intentional that it would make more sense to err on the side of caution and make it a clear error.

All 3 comments

This is a pretty cool idea, but I think it could also be solved in a few easier ways too:

  1. If we add support for lesspipe, it could probably be configured to ls and highlight any directories passed as an input.

  2. A wrapper script that combines bat and exa. Exa is already a well-established project that provides exactly what you're looking for, and it shouldn't be much harder to implement as a wrapper than adding this to your .bash_profile:

bat() {
    local arg
    local files=()
    local dirs=()

    for arg in "$@"; do
        if [ "${arg:0:1}" = "-" ]; then continue; fi
        if [ -d "$arg" ]; then
            dirs+=("$arg")
        elif [ -e "$arg" ]; then
            files+=("$arg")
        fi
    done

    if [ "${#files[@]}" -gt 0 ] && [ "${#dirs[@]}" -gt 0 ]; then
        printf "\x1B[31m[%s error]: %s\x1B[0m%s\n" "$0" "Cannot concatenate files and directories"
        return 1
    fi

    if [ "${#dirs[@]}" -gt 0 ]; then
        exa "${dirs[@]}"
        return $?
    fi

    bat "$@"
    return $?
}

The main downside I can imagine would be confusion when "conbatenating" multiple files: if I accidentally included a directory instead of a file as one of the paths

I would just consider it an error, to be honest. There's such a low likelihood of it being intentional that it would make more sense to err on the side of caution and make it a clear error.

Thanks so much that (almost) worked for me.

I'm using zsh as I'm on macos and I had to use command ... to avoid a recursion error.

What I ended up with was

exa () {
    command exa -l "$@"
    return $?
}

bat() {
    local arg
    local files=()
    local dirs=()

    for arg in "$@"; do
        if [ "${arg:0:1}" = "-" ]; then continue; fi
        if [ -d "$arg" ]; then
            dirs+=("$arg")
        elif [ -e "$arg" ]; then
            files+=("$arg")
        fi
    done

    if [ "${#files[@]}" -gt 0 ] && [ "${#dirs[@]}" -gt 0 ]; then
        printf "\x1B[31m[%s error]: %s\x1B[0m%s\n" "$0" "Cannot concatenate files and directories"
        return 1
    fi

    if [ "${#dirs[@]}" -gt 0 ]; then
        exa "${dirs[@]}"
        return $?
    fi

    command bat "$@"
    return $?
}

Very close to what you had.

I'd be willing to have a crack at a PR

I think this probably isn't true, I'm too busy and the above works well for me, so I doubt I'll be able to make time to work on a fix.

I agree that the wrapper option is probably the best idea. I currently don't see this being integrated into bat itself.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adamtabrams picture adamtabrams  路  3Comments

mjlbach picture mjlbach  路  3Comments

HakubJozak picture HakubJozak  路  3Comments

yum-feng picture yum-feng  路  3Comments

doggy8088 picture doggy8088  路  4Comments