Автоматизируйте копирование между одинаковыми местами похожих деревьев каталогов

Вы можете написать все заглавные буквы, например:

[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*

или используйте именованный класс символов [:upper:]для представления всех прописных букв в текущемlocale:

[[:upper:]]*

Как вы заметили, при использовании диапазона, подобного [B-C], верхний и нижний регистры для одного и того же алфавитного символа располагаются рядом (в соответствии с порядком сортировкиlocale).

0
02.08.2019, 14:06
1 ответ

У утилиты 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
0
28.01.2020, 03:24

Теги

Похожие вопросы