ファイル名が配列にある場合にのみ、ファイルを新しいディレクトリにコピーします。

ファイル名が配列にある場合にのみ、ファイルを新しいディレクトリにコピーします。

私はそれほど情熱的ではありませんが、zsh誰かに簡単なレイアップになると思います。

sourcedirtargetdir次のコマンドを使用してファイルを一括コピーできます。

$ find sourcedir -type f -exec cp {} targetdir \;

cpファイル名が次のいずれかと一致する場合にのみ、この操作を実行できます。

top directory
  fileA            <= directories have same name as single file they enclose
    fileA.pdf                    <= file to move
  another file
    another file.pdf             <= do NOT move
  still133another4544file
    still133another4544file.pdf  <= file to move

文字通り何千ものものを渡す必要がありますが、選択した数個だけを移動するには、名前があり、ファイルに入れるか、スクリプトに直接入れることができます。
単純なシェルスクリプトを維持できます。 Rubyも許可します。

答え1

まず、私が作成したサンプルツリーは次のようになります。

{   pwd
    for   d in ./*/
    do    cd "$d"
          printf '\t%s\n' "${d#??}"
          printf '\t\t%s\n' *
          cd ..
    done
}

/tmp/top
        another file/
                another file.pdf
        fileA/
                fileA.pdf
        otherdir/
                1
                2
                3
        stillanother4544file/
                stillanother4544file.pdf

今何もする必要はありません。サンプルツリーをミラーリングするためにツリーを作成し、いくつかの異常値を追加しました。

しかし、私はこれをするように提案します:

pax -rwis'|^./\([^/]*\)/\(\1\....\)$|\2|' -s'|.*||' . ../tgt

paxこれはデフォルトで-read / riteモード(直接コピーモード)-wでPOSIX標準ユーティリティを呼び出すことです。コピーモードでは、意識モードのpaxようにアーカイブは生成されませんが、その引数で見つかったすべてのファイル(ここでは現在のディレクトリにルートを持つツリーのみ)および/または標準入力((この場合は空))に名前を付けます。という名前のディレクトリです(ここにあります)。tar-w[...pattern...].../tgt

今私はあなたがツリー全体を移動したくないことを知っています。これらのほとんどは-s代替引数で処理されます。sedここで行ったように、正規表現スタイルステートメントに基づいて出力ファイルの名前を変更できます。私は2つの-s交換ドアを使用します。最初は、すべての入力一致の名前を次のように変更します。

./dirname/samename.???

...到着...

samename.???

...出力時にコピーされたすべてのファイルに直接収まるように出力ツリーを平坦化します../tgt./dirname/各ディレクトリの親ディレクトリを維持するには、\2最初の-s置き換えられた部分を&

ファイル名がpax -s正常に一致し、置換によって変更された場合、残りの-s代替パラメータは再試行されず、まだ一致していないファイルにのみ残りの名前変更正規表現が試行されます。これは、現在のディレクトリ内のすべてのファイルが次の種類のパス名を持つことを意味します。

./dirname/samename.???

...最後のパス名コンポーネントと最初の-s代替文とすべての項目を除くすべての項目を正常に選択して削除しました。その他現在のディレクトリのファイルは、2番目の代替ファイルで完全に置き換えられます-s|.*|| -s。これはpax、空の文字列を置き換えるファイル名が処理リストから削除されるためです。

paxすべてのジョブが処理されたら、選択したファイルを実際にコピーする前に最後のジョブを完了する必要があります。これは-i私が指定したインタラクティブな名前変更オプションであり、これがあなたに適していると思います。

からman pax

-i

  • 対話的にファイル名またはアーカイブメンバーの名前を変更します。一致する各プロファイルメンバーについてpatternオペランドまたはファイルオペランドと一致する各ファイルは、ファイル名、ファイルモード、および変更時刻の入力をpax求められます。次に、1行を読みます。この行が空の場合は、ファイルまたはアーカイブメンバーをスキップします。行が単一のピリオドで構成されている場合、ファイルまたはアーカイブメンバーは名前を変更せずに処理されます。それ以外の場合、その名前はその行の内容に置き換えられます。次の場合、ゼロ以外の終了状態で直ちに終了します。/dev/ttypax/dev/ttypaxEOF応答の読み取り中に発生したか、/dev/tty読み取りまたは書き込みのために開くことができません。

ATTENTION: pax interactive file rename operation.
-rw-r--r-- Oct 17 04:30 stillanother4544file.pdf
Input new name, or a "." to keep the old name, or a "return" to skip this file.
Input > .
Processing continues, name unchanged.

ATTENTION: pax interactive file rename operation.
-rw-r--r-- Oct 17 04:30 another file.pdf
Input new name, or a "." to keep the old name, or a "return" to skip this file.
Input >
Skipping file.

ATTENTION: pax interactive file rename operation.
-rw-r--r-- Oct 17 04:30 fileA.pdf
Input new name, or a "." to keep the old name, or a "return" to skip this file.
Input > .
Processing continues, name unchanged.

-iしたがって、現在のディレクトリにある6つのファイルのうち3つだけがインタラクティブな名前変更プロンプトに入ることができます。これら3つのうち2つのみが次のようになります../tgt

ls -l ../tgt

-rw-r--r-- 1 mikeserv mikeserv 0 Oct 17 04:30 fileA.pdf
-rw-r--r-- 1 mikeserv mikeserv 0 Oct 17 04:30 stillanother4544file.pdf

答え2

これらのファイル名を配列に保存し、それらのいずれも含まれていない場合|(エスケープが必要ですが、気にする価値はありませんので、以下の選択肢を参照)、単に配列の要素を連結して結果を次のように使用できます。塊:

myarr=( file1 file2 ... fileN )
lst=${(j:|:)myarr}
cp -v -- **/($~lst) targetdir

たとえば、次のファイルは任意の場所にあります/tmp

caxZN.gif
e8ApF.gif
div2k.js.lzo
cmp2jz.ini

名前を配列に保存すると、結果は次のようになります。

cp -v -- **/($~lst) targetdir
'tmp/div2k.js.lzo' -> 'targetdir/div2k.js.lzo'
'tmp/他のディレクトリ/e8ApF.gif' -> 'targetdir/e8ApF.gif'
'tmp/他のディレクトリ/一two/cmp2jz.ini' -> 'targetdir/cmp2jz.ini'
'tmp/some dir/caxZN.gif' -> 'targetdir/caxZN.gif'

または、今回は1行に1つのファイル名を持つファイルにリストされていると仮定して、配列の行を読み取ってから次のように使用できます。グローバル予選/金利ひもそして修飾子グローバル/選択配列のファイル名のみ:

mylist=(${(f)"$(<list_of_files)"})
cp -- **/*(.e_'(($mylist[(Ie)$REPLY:t]))'_) targetdir

実際には、.通常のファイルのみを選択し(Dリストにドットファイルが含まれている場合は追加されます)、真のファイル名e_'expression'_のみを返します。expression基本名( $REPLY:t)配列の要素です。 mylist、例えば:

print -rl -- **/*(.e_'(($mylist[(Ie)$REPLY:t]))'_)
tmp/div2k.js.lzo
tmp/その他のディレクトリ/e8ApF.gif
tmp/その他のディレクトリ/one two/cmp2jz.ini
tmp/a ディレクトリ/caxZN.gif

もちろん上記の内容はすべてzsh。とにかく、ファイル名を作成し、正しいオプションを渡すのに
時間を費やすなど、独自のソリューションも機能します。find

find . -type f \( -name caxZN.gif -o -name e8ApF.gif -o -name div2k.js.lzo -o -name cmp2jz.ini \) -exec cp -- {} targetdir \;

答え3

$ find sourcedir -type f -name 'file?.pdf' -exec cp {} targetdir \;

このパターンに一致するファイルのみを一致させる必要があります。

答え4

私が正しく理解したら、ディレクトリごとに1つのファイルだけがあり、そのファイルがリストにある場合は移動したいと思います。その場合は、次のようにできます。

while read -r file; do cp sourcedir/*/"$file" targetdir; done < list.txt

ディレクトリもコピーする必要がある場合は、ファイルを読み取ることができます。ファイル拡張子の削除ディレクトリ名を取得し、次をコピーします。

while read -r file; do cp -r sourcedir/"${file%.*}" targetdir; done < list.txt

関連情報