No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fzmv 1.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/env bash
  2. declare -r esc=$'\033'
  3. declare -r c_reset="${esc}[0m"
  4. declare -r c_red="${esc}[31m"
  5. declare dryrun verbose
  6. set -e
  7. err() {
  8. printf "${c_red}%s${c_reset}\n" "$*" >&2
  9. }
  10. die() {
  11. exit 1
  12. }
  13. has() {
  14. local verbose=0
  15. if [[ $1 == '-v' ]]; then
  16. verbose=1
  17. shift
  18. fi
  19. for c; do c="${c%% *}"
  20. if ! command -v "$c" &> /dev/null; then
  21. (( verbose > 0 )) && err "$c not found"
  22. return 1
  23. fi
  24. done
  25. }
  26. has -v fzf || die
  27. fzf() {
  28. command fzf --cycle "$@"
  29. }
  30. pick_files() {
  31. local files fzpick
  32. find . -maxdepth 1 2> /dev/null |
  33. sort -h |
  34. sed '1d; s|^\./||' |
  35. while read -r f; do
  36. if [[ -d "$f" ]]; then
  37. printf '%s/\n' "$f"
  38. elif [[ -L "$f" ]]; then
  39. printf '%s@\n' "$f"
  40. else
  41. printf '%s\n' "$f"
  42. fi
  43. done |
  44. fzf --multi --header='move these files' || return 1
  45. }
  46. pick_destination() {
  47. local cwd browse_dir browse_info query dirs
  48. cwd=$(pwd)
  49. while [[ "$browse_dir" != "$cwd" ]]; do
  50. mapfile -t browse_info < <(
  51. { echo '..'; find . -maxdepth 1 -type d 2> /dev/null; } |
  52. sed 's|^./||' |
  53. sort -h |
  54. fzf --print-query \
  55. --history="${HOME}/.cache/fzmv_history" \
  56. --header="${errors:-move files here}")
  57. query=${browse_info[0]}
  58. browse_dir=${browse_info[1]}
  59. files=( "${browse_info[@]:2}" )
  60. [[ -d "$query" ]] && browse_dir="$query"
  61. [[ ! -d "$browse_dir" ]] && return 1
  62. if [[ "$browse_dir" == '.' && $(realpath "$browse_dir") != "$cwd" ]]; then
  63. realpath "$browse_dir"
  64. break
  65. else
  66. cd "$browse_dir" || die
  67. continue
  68. fi
  69. done
  70. }
  71. while (( $# > 0 )); do
  72. case $1 in
  73. -t|--test) dryrun=true ;;
  74. -v|--verbose) verbose=1 ;;
  75. esac
  76. shift
  77. done
  78. mapfile -t files < <(pick_files)
  79. (( ${#files[@]} > 0 )) || exit 1
  80. destination=$(pick_destination) || exit 1
  81. ${dryrun:+echo} mv ${verbose:+-v} -t "$destination" "${files[@]}"