Skip to content

Instantly share code, notes, and snippets.

@pasela

pasela/.bash_profile

Last active May 10, 2016
Embed
What would you like to do?
[shell] interactive file selection and interactive change directory
# specify your favorite filtering tool
if [[ -z "$INTERACTIVE_SELECTOR" ]]; then
if type fzy >/dev/null 2>&1; then
export INTERACTIVE_SELECTOR=fzy
elif type peco >/dev/null 2>&1; then
export INTERACTIVE_SELECTOR=peco
elif type fzf >/dev/null 2>&1; then
export INTERACTIVE_SELECTOR=fzf
fi
fi
alias isel=interactive-select
function icd()
{
cd "$(interactive-select -dh "$@")"
}
#!/bin/bash
#
# select file and/or directory interactively using $INTERACTIVE_SELECTOR.
#
# USAGE:
# interactive-select [-dfhH] [BASE_DIR]
#
# OPTIONS:
# -d directory only
# -f file only
# -h hide dot-files
# -H include dot-files
#
# ARGS
# BASE_DIR base directory (default: .)
#
# ENV
# INTERACTIVE_SELECTOR interactive filtering tool such as peco, fzf, fzy...
if [[ -z "$INTERACTIVE_SELECTOR" ]]; then
echo "INTERACTIVE_SELECTOR not defined" >&2
exit 1
fi
while getopts dfhH OPT
do
case $OPT in
d) DIR_ONLY=1 ;;
f) FILE_ONLY=1 ;;
h) HIDE_DOT_FILES=1 ;;
H) HIDE_DOT_FILES= ;;
esac
done
shift $((OPTIND - 1))
base=${1:-.}
FIND_OPT=(-print)
if [[ -n "$DIR_ONLY" && -n "$FILE_ONLY" ]]; then
: # do nothing
elif [[ -n "$DIR_ONLY" ]]; then
FIND_OPT=(-type d "${FIND_OPT[@]}")
elif [[ -n "$FILE_ONLY" ]]; then
FIND_OPT=(-type f "${FIND_OPT[@]}")
fi
if [[ -n "$HIDE_DOT_FILES" ]]; then
FIND_OPT=(-type d -name . -or -name ".*" -prune -or "${FIND_OPT[@]}")
fi
selected=$(cd "$base" && find . "${FIND_OPT[@]}" | \
sed -e 's#^./##' | $INTERACTIVE_SELECTOR) && echo "$base/$selected"
@pasela

This comment has been minimized.

Copy link
Owner Author

@pasela pasela commented May 10, 2016

小難しいことしている理由

  • 指定パスが含まれると絞り込みの時にうざい(下記参照)
  • .gitとか邪魔(-hで除外、-Hで含める(-h上書き用))
  • ファイルだけ(-f)、ディレクトリだけ(-d)とか簡単に指定したい

findが複雑になった過程

普通にfindすると指定したパスも付いた状態で出力されるので絞り込むときに余計にマッチしたりして邪魔になる。

$ find /usr/local/lib -type d -print
/usr/local/lib
/usr/local/lib/zsh
/usr/local/lib/guilt
/usr/local/lib/pkgconfig
/usr/local/lib/java

-printf%Pを使うとちょうど指定したパス以下のみ出力してくれる……が、-printfはGNU版にしかなかった。

$ find /usr/local/lib -type d -printf "%P\n"

zsh
guilt
pkgconfig
java

仕方ないのでsedで先頭だけ削ろうとしたら~/fooやシンボリックリンクの時にうまくいかなかったのでcdしてからfind .するようにした。

$ cd /usr/local/lib && find . -name ".*" -prune -or -type d -print

そうしたら、ドットファイルを除外する-name ".*" -pruneがカレントの.に引っかかるせいなのか何も出てこなくなった。
なので先頭に-name . -orを入れることになった。

$ cd /usr/local/lib && find . -name . -or -name ".*" -prune -or -type d -print
./zsh
./guilt
./pkgconfig
./java

で、./sedで削って…という感じでこんなに長くなった。

$ cd /usr/local/lib && find . -name . -or -name ".*" -prune -or -type d -print | sed -e 's#^./##'
zsh
guilt
pkgconfig
java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.