Maybe you can make something more general-purpose with "aliases" and "templates", e.g.,
# add alias "shortcut"
rclone alias --add shortcut "backend shortcut %(config --get remote %1) %(backend encode %1 %2) %(backend encode %1 %3)"
# remove alias "shortcut"
rclone alias --remove shortcut
# use alias "shortcut"
rclone alias shortcut crypt: file shortcut
?
Anyway, here's another shell script:
#!/bin/bash
# assume crypt remote CRYPT_REMOTE mounted at MOUNTPOINT with drive remote DRIVE_REMOTE
DRIVE_REMOTE="drive:rclone"
CRYPT_REMOTE="crypt:"
MOUNTPOINT="/mnt/remote"
print_usage() {
cat <<EOF
Usage: shortcut SOURCE DESTINATION
or: shortcut SOURCE... DIRECTORY
Shortcut SOURCE to DESTINATION, or multiple SOURCE(s) to DIRECTORY.
See the top of the script for configuration parameters.
EOF
exit 0
}
die() {
echo "$@" >&2
exit 1
}
convert_path() {
crypt_path="$1"
drive_path=($(IFS=/ eval rclone backend encode '"$CRYPT_REMOTE"' '$crypt_path'))
IFS=/ eval echo '"${drive_path[*]}"'
}
[ $# -eq 0 ] && print_usage
[ $# -lt 2 ] && die "error: two or more arguments required"
for i in "${@:1:$#-1}"; do
tmp="$(readlink -m "$i")"
if [ ! -e "$tmp" ] || [ "$tmp" = "${tmp#$MOUNTPOINT}" ]; then
die "error: $i does not exist or is not within \$MOUNTPOINT"
fi
done
tmp="$(readlink -m "${!#}")"
if [ "$tmp" = "${tmp#$MOUNTPOINT}" ]; then
die "error: ${!#} is not within \$MOUNTPOINT"
fi
if [ $# -eq 2 ]; then
if [ -f "$2" ]; then
die "error: $2 exists already"
fi
tmp="${2%/}/$(basename "$1")"
if [ -f "$1" ] && [ -d "$2" ] && [ -f "$tmp" ]; then
die "error: $tmp exists already"
fi
tmp="$(dirname "$2")"
if [ ! -d "$tmp" ]; then
die "error: $tmp does not exist or is not a directory"
fi
else
if [ ! -d "${!#}" ]; then
die "error: ${!#} does not exist or is not a directory"
fi
fi
# normalize, just in case
DRIVE_REMOTE="${DRIVE_REMOTE%/}"
CRYPT_REMOTE="${CRYPT_REMOTE%/}"
MOUNTPOINT="${MOUNTPOINT%/}"
rename_mode="false"
if [ $# -eq 2 ] && [ ! -e "$2" ]; then
# special case: shortcut-rename file/directory
rename_mode="true"
fi
dst_top_path="$(readlink -f "${!#}")"
dst_path="$dst_top_path"
for i in "${@:1:$#-1}"; do
src_top_path="$(readlink -e "$i")"
[ "$rename_mode" = "false" ] && dst_path="$dst_top_path/$(basename "$src_top_path")"
while read -r path; do
src_path="$(readlink -e "$path")"
tmp="${src_path#$src_top_path}"
shared_path="${tmp#/}"
if [ -d "$src_path" ]; then
#echo mkdir "${dst_path}${shared_path:+/$shared_path}"
mkdir "${dst_path}${shared_path:+/$shared_path}"
#echo touch -r "${src_path}" "${dst_path}${shared_path:+/$shared_path}"
touch -r "${src_path}" "${dst_path}${shared_path:+/$shared_path}"
elif [ -f "$src_path" ]; then
src_crypt_path="${src_path#$MOUNTPOINT/}"
src_drive_path="$(convert_path "$src_crypt_path")"
dst_crypt_path="${dst_path#$MOUNTPOINT/}${shared_path:+/$shared_path}"
dst_drive_path="$(convert_path "$dst_crypt_path")"
#echo rclone backend shortcut "$DRIVE_REMOTE" "[$src_crypt_path]" "[$dst_crypt_path]"
#echo rclone backend shortcut "$DRIVE_REMOTE" "$src_drive_path" "$dst_drive_path"
rclone backend shortcut "$DRIVE_REMOTE" "$src_drive_path" "$dst_drive_path" >/dev/null
fi
done < <(find "$i")
done
I modelled it on "cp -a", except that it shortcuts files instead of copying them and only preserves modification times (for directories). It never creates shortcuts to directories. You can use it like this, assuming /mnt/remote
is your crypt:
mountpoint.
The start state:
# cd /mnt/remote
# find
.
./archive
./archive/linux-distros
./archive/linux-distros/debian
./archive/linux-distros/debian/buster.iso
./archive/linux-distros/devuan
./archive/linux-distros/devuan/ascii.iso
./archive/linux-distros/devuan/beowulf.iso
Shortcut archive/linux-distros
, keeping linux-distros
as the destination name:
# shortcut archive/linux-distros/ .
# find
.
./archive
./archive/linux-distros
./archive/linux-distros/debian
./archive/linux-distros/debian/buster.iso
./archive/linux-distros/devuan
./archive/linux-distros/devuan/ascii.iso
./archive/linux-distros/devuan/beowulf.iso
./linux-distros
./linux-distros/debian
./linux-distros/debian/buster.iso
./linux-distros/devuan
./linux-distros/devuan/ascii.iso
./linux-distros/devuan/beowulf.iso
Shortcut archive/linux-distros/devuan
, using my-linux-distro
as the destination name:
# shortcut archive/linux-distros/devuan/ my-linux-distro
# find
.
./archive
./archive/linux-distros
./archive/linux-distros/debian
./archive/linux-distros/debian/buster.iso
./archive/linux-distros/devuan
./archive/linux-distros/devuan/ascii.iso
./archive/linux-distros/devuan/beowulf.iso
./linux-distros
./linux-distros/debian
./linux-distros/debian/buster.iso
./linux-distros/devuan
./linux-distros/devuan/ascii.iso
./linux-distros/devuan/beowulf.iso
./my-linux-distro
./my-linux-distro/ascii.iso
./my-linux-distro/beowulf.iso
Shortcut archive/linux-distros/devuan/beowulf.iso
, keeping beowulf.iso
as the destination name:
# shortcut archive/linux-distros/devuan/beowulf.iso .
# find
.
./archive
./archive/linux-distros
./archive/linux-distros/debian
./archive/linux-distros/debian/buster.iso
./archive/linux-distros/devuan
./archive/linux-distros/devuan/ascii.iso
./archive/linux-distros/devuan/beowulf.iso
./beowulf.iso
./linux-distros
./linux-distros/debian
./linux-distros/debian/buster.iso
./linux-distros/devuan
./linux-distros/devuan/ascii.iso
./linux-distros/devuan/beowulf.iso
./my-linux-distro
./my-linux-distro/ascii.iso
./my-linux-distro/beowulf.iso
Shortcut archive/linux-distros/devuan/beowulf.iso
, using linux.iso
as the destination name:
# shortcut archive/linux-distros/devuan/beowulf.iso linux.iso
# find
.
./archive
./archive/linux-distros
./archive/linux-distros/debian
./archive/linux-distros/debian/buster.iso
./archive/linux-distros/devuan
./archive/linux-distros/devuan/ascii.iso
./archive/linux-distros/devuan/beowulf.iso
./beowulf.iso
./linux-distros
./linux-distros/debian
./linux-distros/debian/buster.iso
./linux-distros/devuan
./linux-distros/devuan/ascii.iso
./linux-distros/devuan/beowulf.iso
./linux.iso
./my-linux-distro
./my-linux-distro/ascii.iso
./my-linux-distro/beowulf.iso
You can shortcut any number of files and directories at the same time, e.g., instead of the initial
# shortcut archive/linux-distros/ .
you could have run
# mkdir linux-distros
# shortcut archive/linux-distros/debian archive/linux-distros/devuan linux-distros
The script is not very fast, but it does work. I considered using the async rc
interface, but then bash probably wouldn't be the right tool for the job.
Now I need some way to determine whether a file is a shortcut or not. Without it, shortcuts are dangerous because you cannot tell whether you're editing a copy of a file or the one original through a shortcut.
Perhaps what's needed is a drive
-specific version of ls*
that returns this piece of information?