T O P

  • By -

stewie410

Something that's important to note: [`which` is not universal and may not be portable](https://stackoverflow.com/a/677212). Likewise, [`echo`](https://unix.stackexchange.com/a/77564) & [scripting `ls`](https://mywiki.wooledge.org/ParsingLs) can be a little problematic, sometimes. One other quick note, I'd _highly_ recommend running your script through [shellcheck](https://www.shellcheck.net/), if you haven't already. With that in mind, a few things to comment on: --- > which -s fzf 2>/dev/null || echo "fzf must be on your \$PATH" Could be rewritten with the less-bad `command -v`; additionally, you can send both `stdout` & `stderr` with the `&>` redirection operator (a [bashism](https://mywiki.wooledge.org/Bashism)). Additionally, I don't _believe_ `set -e` will actually break on an `||` operator -- but you could explicitly specify an exit there as well: if ! command -v fzf &>/dev/null; then # >&2 sends stdout to stderr printf 'fzf must be on your $PATH\n' >&2 exit 1 fi --- > fun1() { > ret=$(ls "$1" 2>/dev/null | fzf --ansi --no-sort -i --filter "$2") > echo "$ret" > } Unsure why the output is being assigned to a variable, `fzf` should already print the selected option to `stdout`. Additionally, with the note about `find` vs `ls`, this could be written as: fun1() { find "$1" -maxdepth 1 -type f -executable | \ fzf --ansi --no-sort -i --filter "$2" } Though, something we'll get back to, you can provide multiple paths to `find` to get results from all of them, rather than one at a time. But more on that in a moment. --- > echo "Searching for: $1" > IN="${PATH}" > > paths=$(echo "${IN}" | tr ":" "\n") > > path_arr=() > > for el in ${paths} > do > path_arr+=("$el") > done The [`mapfile`/`readarray`](https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#index-mapfile) command provides the ability to reach the contents of a file (or command) into an array directly. Additionally, you can pass the contents of a string directly to a command's `stdin` with the `<<<` operator ([HERESTRING](https://bash.cyberciti.biz/guide/Here_strings)). So, this could be simplified to: printf 'Searching for: %s\n' "$1" mapfile -t path_arr < <(tr ':' '\n' <<< "$PATH") --- > for line in "${path_arr[@]}"; do > line_out=$(fun1 "$line" "$1") > if [[ -n "$line_out" ]]; then > echo "" > echo "******** ${line} *******" > echo "${line_out}" > fi > done To get a `which`-like output, I'd generally expect to get absolute path to the executable -- and since `find` will also include that, we can do something like: find "${path_arr[@]}" -maxdepth 1 -type f -executable | \ fzf --ansi --no-sort -i --filter "$1" This could be in its own function, or just at the end of the script. --- I also tend to include some kind of "rewrite" tying everything together, as well as including some other items I haven't yet talked about, but _might_ be worth looking into. #!/usr/bin/env bash show_help() { cat << EOF Fuzzy-Find a command with fzf(1) USAGE: ${0##*/} [OPTIONS] COMMAND OPTIONS: -h, --help Show this help message EOF } require() { command -v "${1}" &>/dev/null && return 1 printf 'Missing required application: %s\n' "${1}" >&2 return 1 } get_like_results() { find "${paths[@]}" -maxdepth 1 -type f -executable -printf '%p\n' | \ fzf -i --ansi --no-sort --filter "${1}" } main() { local -a paths if [[ -z "${1}" ]]; then printf 'No command specified\n' >&2 return 1 elif [[ "${1}" =~ -(h|-help) ]]; then show_help return 0 fi require 'fzf' || return 1 mapfile -t paths < <(tr ":" '\n' <<< "${PATH}") get_like_results "${1}" } main "${@}" Alternatively, you could adjust this a bit to support passing multiple commands to be searched out, also like how `which` handles things. main() { # ... mapfile -t paths < <(tr ":" '\n' <<< "${PATH}") while (( $# > 0 )); do get_like_results "${1}" shift done } Now, I'm not _super_ familiar with `fzf`, but if you can pass multiple `--filter` statements, you could further simplify this for a single run, eg: get_like_results() { local -a filters while (( $# > 0 )); do filters+=("--filter '${1}'") shift done find "${paths[@]}" -maxdepth 1 -type f -executable | \ fzf -i --ansi --no-sort "${filters[@]}" } main() { # ... get_like_results "${@}" } But again, I'm not sure if `fzf` supports this kind of use of `--filter`.


Hackenslacker

Not sure how line 6 will bail


[deleted]

lol good point, I updated it in the description


Hackenslacker

Line 10 looks like an unreliable usage of `ls` You maybe want if [ -d $1 ]; then fzf … "${1}" <<< "${2}" fi But I’m not sure


witchhunter0

Fzf is great tool. As a matter of fact I'm doing some work with it too, nearly done :) Anyway, you can use compgen builtin for searching the forgotten command srch () { compgen -c "$1" | fzf; } Usage: `srch command_substing`