
ファイル名のリスト(一部はスペースを含む)を含み、そのファイルが属するフルファイルパスのリスト(スペースを含む)をランダムな順序で含む2つのテキストファイルとがあるとしますsrc.txt
。たとえば、dest.txt
src.txt
/src/dir/
dest.txt
src.txt:
file 1.jpg
file_2.html
file 3.jpg
ターゲット.txt:
/dest/dir 1/file 3.jpg
/dest/file4.txt
/dest/file 5.txt
/dest/dir 2/file 1.jpg
/dest/file_2.html
シェルで一括移動操作を実行するには?ソースファイルを繰り返しながらwhile read
そのコマンドを使用する必要があると確信していますが、ここではこれが必須か必須mv
かわかりません。空白文字の解析エラーが発生し続けます。grep
sed
cannot stat...
答え1
そしてzsh
:
src=(${(f)"$(<src.txt)"})
for f (${(f)"$(<dest.txt)"})
(($src[(Ie)$f:t])) && mv /src/dir/$f:t $f
これは配列内の各ファイルを読み取り、次に配列内の各要素を読み取ります。「目的地」basename(すべての先行パス名コンポーネントを削除する修飾子)が次の:t
場合zsh
「源泉」配置し、ファイルを移動します。練習を実行するには、mv
に置き換えますprintf '"%s" -> "%s"\n'
。
これで、以下を実行することもできます(まだzsh
)。
for f (${(f)"$(grep -Ff src.txt dest.txt)"})
mv /src/dir/$f:t $f
src.txt
inのファイル名がパスリストのディレクトリ名(またはその名前の一部)と一致しないinのファイル名やinなどのパスはdest.txt
、data1
src.txt
/path/data1_dir/some_file
dest.txt
grep
/filename$
F
dest.txt
src.txt
bash
4
readarray -t files < <(sed 's|[[\.*^$/]|\\&|g;s|.*|/&$|' src.txt | grep -f- dest.txt)
for f in "${files[@]}"; do mv /src/dir/"${f##*/}" "$f"; done
答え2
改行が許可されている区切り文字の場合は、POSIXシェルで次のものが確実に機能する必要があります。
IFS='
';set -f
for f in $(cat <"$destfile")
do [ -e "./${f##*/}" ] ||
[ -h "./${f##*/}" ] &&
mv "./${f##*/}" "$f"
done
このソリューションには2つの考えられる問題があります。
入力ファイルのサイズが大きすぎるため、一度に分割することはできません。
- 私のシステムでは、入力が数万行に達するまで、これはまったく真剣に考慮する価値はありません。
ファイル名は
$destfile
現在のディレクトリにありますが、いいえ何があっても感動します。- このソリューションは両方の入力ファイルの比較を完全に放棄し、
$destfile
現在のディレクトリにある最後のパス名コンポーネントの存在のみを確認するため、意図せず一致する可能性のあるファイル名は考慮しないでください。
- このソリューションは両方の入力ファイルの比較を完全に放棄し、
最初の問題のみを処理する必要がある場合:
sed -ne"s|'|'"'\\&&|g' <"$destfile" \
-e "s|.*/\([^/].*\)|_mv './\1' '&'|p" |
sh -c '_mv(){ [ -e "$1" ]||[ -h "$1" ]&& mv "$@";};. /dev/fd/0'
その場合は、最後に削除して次のものを使用sh
できます。dash
. /dev/fd/0
sed ... | sh -cs '_mv(){ ...;}'
...dash
奇妙なことに、何の苦情もなくコマンドラインと標準入力呼び出しオプションの両方を処理するためです。移植性は良くありませんが、. /dev/fd/0
移植性に優れていますが、標準に厳密に準拠していません。
2番目の質問が質問の場合:
export LC_ALL=C
sed -ne'\|/$|!s|.*/\(.*\)|\1/&|p' <"$destfile" |
sort -t/ -k1,1 - ./"$srcfile" | cut -d/ -f2- |
sed -e "\|/|!N;\|\n.*/|!d" \
-e "s|'|'"'\\&&|g' \
-e "s|\n|' '|;s|.*|mv './&'|" | sh
...すべてのファイル名が。./"$srcfile"
1つの2つの比較のうち短い項目が一番上に表示されるため、最初のフィールドのみが重要で、ファイル名が各パス名の先頭に追加されると、2つの項目のマージ操作が実行されます。ファイルは次の順序を出力します。"$destfile"
sort
"$destfile"
sort
$srcfile: no /
$destfile: match
$destfile: unique
$destfile: unique
...
$srcfile: no /
$destfile: match
$destfile: unique
...したがって、一致しない行で始まる行のペアにのみ注意してください/
。
答え3
while read i; do echo cp \""$i"\" \"$(grep "/$i$" dst.txt)\"; done < src.txt
これにより、意図した内容が印刷されます。echo
実際にファイルをコピーするには削除してください。
答え4
スクリプト行はスクリプトを生成し、スクリプトを生成します。
この例では、sed
onへの最初の呼び出しを使用してファイルをコピーするためのシェルスクリプトを生成するために実行されるsrc.txt
2番目のスクリプトを生成します。sed
dest.txt
次の行は次のとおりです。
$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt #| sh -x
そして出力:
cp "file 3.jpg" "/dest/dir 1/file 3.jpg";
cp "file 1.jpg" "/dest/dir 2/file 1.jpg";
cp "file_2.html" "/dest/file_2.html";
#| sh
コマンドの最後にあるコメントを参照してください。これにより、コマンドを試してその内容を確認することができ、正しく機能するとパイプのコメントを外してsh
実際にファイルをコピーできます。
内部 sed コマンドは src.txt に基づいて sed スクリプトを作成します。生成されたスクリプトの最初の行は次のとおりです。
/\/file 1.jpg$/ { s/^/cp file 1.jpg /; p; }
仕組みは次のとおりです。
入力する:
$ cat src.txt
file 1.jpg
file_2.html
file 3.jpg
$ cat dest.txt
/dest/dir 1/file 3.jpg
/dest/file4.txt
/dest/file 5.txt
/dest/dir 2/file 1.jpg
/dest/file_2.html
最初のsed
電話。これは、2番目の呼び出しによって解釈される生成されたスクリプトを示していますsed
。
$ sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt
/\/file 1.jpg$/ { s/^/cp "file 1.jpg" "/; s/$/";/; p; }
/\/file_2.html$/ { s/^/cp "file_2.html" "/; s/$/";/; p; }
/\/file 3.jpg$/ { s/^/cp "file 3.jpg" "/; s/$/";/; p; }
最初のコマンドの出力をsed
2番目の呼び出しに渡されるコマンドラインのスクリプトとして使用するには、シェルコマンドの置き換えを使用しますsed
。
$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt
cp "file 3.jpg" "/dest/dir 1/file 3.jpg";
cp "file 1.jpg" "/dest/dir 2/file 1.jpg";
cp "file_2.html" "/dest/file_2.html";
sh -x
次に、xtraceオプション()を使用してsedの出力をシェルにパイプします。ファイルが存在しないためエラーが発生します。
$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt | sh -x
+ cp file 3.jpg /dest/dir 1/file 3.jpg
cp: cannot stat ‘file 3.jpg’: No such file or directory
+ cp file 1.jpg /dest/dir 2/file 1.jpg
cp: cannot stat ‘file 1.jpg’: No such file or directory
+ cp file_2.html /dest/file_2.html
cp: cannot stat ‘file_2.html’: No such file or directory