-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzclone
More file actions
executable file
·134 lines (103 loc) · 4.67 KB
/
Copy pathzclone
File metadata and controls
executable file
·134 lines (103 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/bin/bash
# set -x
export PS4='`[[ $? == 0 ]] || echo "\e[1;31;40m($?)\e[m\n "`:.$LINENO:'
red="`git config --get-color '' 'red bold'`";
grn="`git config --get-color '' 'green bold'`";
blu="`git config --get-color '' 'blue bold'`";
rst="`git config --get-color '' 'reset'`";
usage() {
printf >&2 "WARNING: %s\n\n" "$*"
cat <<-EOF >&2
Usage:
zclone copy|sync path1 path2
where path1 and path2 can be local or remote, e.g., Downloads, or
server:Downloads. (However, if you want to specify the root of a remote
server as the destination, please use "server:." instead of "server:")
If you are currently using ssh, converting an ssh host entry in
~/.ssh/config into an rclone remote in ~/.config/rclone/rclone.conf is not
that hard. The general template for keyed access with ssh-agent is:
[remotename]
type = sftp
user = bob
host = 192.168.1.1
port = 2222 # only needed if it is not 22
However, be aware that rclone does have a few minus points:
- rclone does NOT do rsync-style delta xfr
- rclone does NOT handle metadata for directories, only files (even that
only when the -M flag is used); do not use to copy "system" files
(Also, "--create-empty-src-dirs" should really be optional, but for now
we're forcing it in all cases.)
EOF
exit 1
}
[[ -z $1 ]] && usage
# ----------------------------------------------------------------------
bindf1="--bind=f1:execute(exec > /dev/tty ; exec 2>&1 zclone | less -c)"
# ----------------------------------------------------------------------
# 2025-04-06 add "-l" to "lsf" (and remove "--skip-links")
get_source_paths() {
export FZF_DEFAULT_OPTS="--exact --no-sort --reverse --info=inline --multi"
bindd="--bind=ctrl-d:reload(rclone lsf -R -l --dirs-only \"$1\")"
bindf="--bind=ctrl-f:reload(rclone lsf -R -l --files-only \"$1\")"
h=$(printf "$header" "$1")
rclone lsf -R -l --dirs-only "$1" |
fzf "$bindf1" "$bindd" "$bindf" --expect 'esc,ctrl-r,ctrl-t,ctrl-c' --bind 'ctrl-a:select-all' --header "$h"
}
# ----------------------------------------------------------------------
get_dest_path() {
export FZF_DEFAULT_OPTS="--exact --no-sort --reverse --info=inline"
bindd="--bind=ctrl-d:reload(rclone lsf -R --dirs-only \"$1\")"
h=$(printf "$header" "$1")
rclone lsf -R --skip-links --dirs-only "$1" |
fzf "$bindf1" "$bindd" --expect 'ctrl-t,ctrl-c' --header "$h"
}
# ----------------------------------------------------------------------
op=$1; shift
[[ $op =~ ^(copy|sync|move)$ ]] || usage "Only copy, sync, or move allowed"
# edge case...
[[ $2 =~ ^[a-z0-9_-]+:$ ]] && usage "Please use '$2.' instead of '$2' if no additional path component is required"
DEST="$2"
# ----------------------------------------------------------------------
header="${blu}SOURCE SELECTION${rst}
${blu}F1${rst} for help
${blu}CTRL-T${rst} to use ${grn}%s${rst} as the source
otherwise select one or more dirs or files using ${blu}TAB${rst} then hit ${blu}ENTER${rst} (${blu}CTRL-A${rst} will select all)
${blu}CTRL-D/F${rst} to switch between ${red}d${rst}irectories and ${red}f${rst}iles
${blu}CTRL-R${rst} to switch to the selected directory and ${red}r${rst}eload; see help for more info on this
${blu}Esc${rst} to go back up one level
${blu}CTRL-C${rst} to abort"
readarray -t sources < <(get_source_paths "$1")
while :; do
if [[ ${sources[0]} == ctrl-r ]]; then
set -- "$1"/"${sources[1]}"
set -- "${1%/}"
elif [[ ${sources[0]} == esc ]]; then
set -- "${1%/*}"
else
break
fi
readarray -t sources < <(get_source_paths "$1")
done
for i in "${sources[@]}"; do echo "(s=$i)"; done
[[ ${sources[0]} == ctrl-c ]] && exit
[[ ${sources[0]} == ctrl-t ]] && sources=("" "**")
# ^^
# was $1, Ahen $1/, then ./
# if you change it, make sure to test with top level as well as sub-dirs
[[ ${sources[1]} =~ ^$ ]] && exit
# ----------------------------------------------------------------------
header="current path: ${red}$DEST${rst}
${blu}DESTINATION SELECTION${rst}
${blu}F1${rst} for help
${blu}CTRL-T${rst} to use ${grn}%s${rst} as the destination
otherwise select a destination directory and hit ${blu}ENTER${rst}
${blu}Esc${rst} or ${blu}CTRL-C${rst} to abort"
readarray -t dest < <(get_dest_path $DEST)
[[ ${dest[0]} == ctrl-c ]] && exit
[[ ${dest[0]} == ctrl-t ]] && DEST="$DEST" || DEST="$DEST/${dest[1]}"
# ----------------------------------------------------------------------
# 2025-04-06 "-l" again
printf "%s\n" "${sources[@]:1}" |
sed -e 's,/$,/**,' |
tee >(cat >&2) |
{ set -x; rclone $op --stats 100ms -P --include-from=- --create-empty-src-dirs -l "$1" "$DEST"; }