ファイルリストをターゲットインデックスと一致させて移動します。

ファイルリストをターゲットインデックスと一致させて移動します。

ファイル名のリスト(一部はスペースを含む)を含み、そのファイルが属するフルファイルパスのリスト(スペースを含む)をランダムな順序で含む2つのテキストファイルとがあるとしますsrc.txt。たとえば、dest.txtsrc.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かわかりません。空白文字の解析エラーが発生し続けます。grepsedcannot 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.txtinのファイル名がパスリストのディレクトリ名(またはその名前の一部)と一致しないinのファイル名やinなどのパスはdest.txtdata1src.txt/path/data1_dir/some_filedest.txtgrep/filename$Fdest.txtsrc.txtbash4

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

スクリプト行はスクリプトを生成し、スクリプトを生成します。

この例では、sedonへの最初の呼び出しを使用してファイルをコピーするためのシェルスクリプトを生成するために実行されるsrc.txt2番目のスクリプトを生成します。seddest.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; }

最初のコマンドの出力をsed2番目の呼び出しに渡されるコマンドラインのスクリプトとして使用するには、シェルコマンドの置き換えを使用します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

関連情報