Вы можете написать все заглавные буквы, например:
[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*
или используйте именованный класс символов [:upper:]
для представления всех прописных букв в текущемlocale
:
[[:upper:]]*
Как вы заметили, при использовании диапазона, подобного [B-C]
, верхний и нижний регистры для одного и того же алфавитного символа располагаются рядом (в соответствии с порядком сортировкиlocale
).
У утилиты rsync
есть опция -R
, которая может несколько помочь вам здесь, но вам нужно передать весь исходный путь и сообщить rsync
о какой части исходного пути, который вы хотите рассматривать как «корневой» фрагмент. Вы предоставляете эту информацию, вставляя ./
в нужную точку исходного пути.
В вашем примере «корневая» часть — это просто myroot/
, поэтому ваша команда будет выглядеть как:
myroot/a/b/c$ rsync -R myroot/./a/b/c/myfile remoteroot
Я предполагаю, что вы хотели бы иметь простой способ указать «корневую» часть текущего пути к каталогу в любом сложном случае.
Надежным, но все же относительно простым способом будет использование номера глубины пути. Например, на bash
вы можете сделать что-то вроде:
/path/to/myroot/a/b/c$ rsync -R "$(idx=4; IFS=/; set -- $PWD ; printf '%s/' "${@:1:idx}". "${@:idx+1}")"/myfile remoteroot
# ^--- 4th piece of path counted as number of slashes in $PWD
Конечно, не так кратко, как одна -строчка, но эту подстановку команд можно было бы сделать функцией в вашем .bashrc
файле, например:
rootidx() {
local idx="$1"
# make Bash perform Word Splitting on / character
local IFS=/ # make IFS local here, so to not affect global IFS
# set function's arguments to each piece of current directory path,
# as split on $IFS
set -- $PWD
# print from first argument up to the one indicated by wanted index,
# then a./, then from wanted index onwards
printf '%s/' "${@:1:idx}". "${@:idx+1}"
}
используется как:
/path/to/myroot/a/b/c$ rsync -R "$(rootidx 4)"/myfile remoteroot
В качестве альтернативы, чтобы определить «корень» в указанной строке полного пути,простой, а также совместимый с POSIX -способ может быть похож на:
/path/to/myroot/a/b/c$ rsync -R "${PWD%%/myroot/*}/myroot/./${PWD#*/myroot/}"/myfile remoteroot
, который использует расширение параметра поверх $PWD
для вставки ./
в точку, где часть строки myroot
впервые встречается в текущем пути к каталогу.
Однако, как бы ни было просто расширение параметра, необходимо быть осторожным при указании соответствующей промежуточной части пути к текущему каталогу, в противном случае конкретное расширение не будет работать должным образом и вместо этого будет объединить весь текущий каталог с собой и указанной строкой в середине.
Расширение параметров также можно сделать функцией, что также помогает сделать его немного более надежным, как в:
rootname() {
[[ "$PWD" == */"$1"/* ]] && \ # check presence of string as intermediate path
printf '%s' "${PWD%%/${1}/*}/${1}/./${PWD#*/${1}/}" || \ # apply the injection, or
printf '%s -not valid-' "$1" # try to produce an unlikely filename so to make `rsync` fail
}
используется как:
/path/to/myroot/a/b/c$ rsync -R "$(rootname myroot)"/myfile remoteroot
Наконец, если у вас есть инструменты GNU, а также оболочка, которая понимает расширение пути **
, вы также можете использовать эти функции для операций локального копирования с cp
. Например, как:
/path/to/myroot/a/b/c$ (shopt -s globstar; cd "$(rootidx 4)" && cp --parents **/myfile otherpath)
Команда shopt -s globstar
включает bash
расширение **
.
Естественно, вы могли бы сделать и это функцией:
smartcp() {
# FIXME: some sanity checks over arguments here
# TODO: detect type of first argument, and use either rootidx or rootname accordingly
(shopt -s globstar; cd "$(rootidx "$1")" && cp --parents **/"${2}" "$3")
}
тогда:
/path/to/myroot/a/b/c$ smartcp 4 myfile otherpath