私は2台のコンピュータに大きなファイルシステムツリーを維持しており、多くの場合、あるコンピュータから別のコンピュータに1つまたは複数のファイルをコピーする必要があります。
長く同じパスを入力しなくても、2つのツリーの同じ場所間で自動的にコピーできますか?
たとえば、を指定せずにmyroot/a/b/c
ファイルをコピーしたいとします。remoteroot/a/b/c
a/b/c
このような:
myroot/a/b/c$: smartcopy myfile --destination-root remoteroot
答え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