web-dev-qa-db-ja.com

ワイルドカードで複数のファイルをコピーするにはどうすればよいですか?

ABC。*の中に多数のファイルが入ったフォルダーがあります(そのようなファイルは約100個あります)。それらをすべてDEF。*で始まる名前の新しいファイルに複製したい

だから、私は欲しい

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

にコピー

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

(BASHまたは類似の)バッチコマンドでこれを行う最も簡単な方法は何ですか? sed、awk、またはxargsを含むことを考えていますが、構文を理解するのが困難です。 Pythonスクリプトを記述できますが、複雑すぎないコマンドラインソリューションがあると思います。

45
Octopus

Bashでこのようなものはどうですか:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

cpコマンドの前にechoを置くことでテストできます。

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done
44
Magnus

多数のファイルでこれを効率的に行うには、ファイルごとに異なるcpプロセスを開始しないことをお勧めします。 1つの方法は、prenameを使用してそれらをコピーし、名前を変更することです(renameは、Debianベースのディストリビューションでは、デフォルトでこれにシンボリックリンクされています)。これとLinuxを使用するmktemp

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

更新

実際にはpaxを使用する方がよいかもしれません。

pax -rws '/^ABC/DEF/' ABC.* .

残念ながら、paxはPOSIXとLinux Standard Baseの両方ですが、現在、デフォルトで含まれているディストリビューションはほとんどありません。

8
Graeme

tarはこれを非常に高速に行います。

テスト

まず、2つのディレクトリと10個のファイルを作成しました。

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

それから私はそれらをコピーしました:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

変換

したがって、GNU tarは、ファイル名を変更するためのsed --transform=EXPRESSIONを受け入れます。これにより、一部のファイルのみを名前変更することもできます。たとえば、次のようになります。

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

これが利点の1つです。

ストリーム

また、これは2つのtarプロセスのみであり、ファイル数に関係なく変更されないことを考慮してください。

tar | tar

tarは、思い通りに最適化されています。これは問題のある引数の数や暴走した子プロセスを持つことは決してありません。これはA> B完了です。

議論

ここでは、2つのtarプロセス間で7つの異なる引数を組み合わせて使用​​しています。最も重要なものが最初にここにリストされています:

- stdout/stdin-これはtarに、入力または出力をストリーミングすることを通知しますstdin/stdoutへのストリーミングまたはビルド中かどうかに応じて正しく解釈されますアーカイブを抽出します。

-c create-これはtarにアーカイブをビルドするように指示します。 tarが期待する次の引数は...

-f file-tarがテープデバイスなどではなくfileオブジェクトで動作することを指定します。上記のように、このファイルで使用するファイルはstdin/stdoutです。つまり、|pipeです。

./* all $ PWD/files-アーカイブ引数が最初に来ることを除いて、ここでは説明しすぎないので、-./*

...そして|pipeの反対側...

-C change directory-これは、他のアクションを実行する前に、指定したディレクトリに変更する必要があることをtarに通知するので、抽出する前に、単にcd ../test2にするだけです。

--transform='s/ed/EXPR/'-すでに述べたように、これは名前の変更を行いました。しかし、ドキュメントは、それがsed式または//flagを取ることができることを示しています。

-x extract-tarがターゲットディレクトリに変更され、名前変更の指示を受け取った後、-f - |pipeアーカイブファイルから現在のディレクトリにすべてのファイルを抽出するように指示します。謎はありません。

5
mikeserv

あまり標準的でないツールを使用してもかまわない場合は、この種のタスク用に作成された mmv (大量移動)を使用することをお勧めします。スイートの一部であるmcp(大量コピー)を使用すると、簡単に

mcp "ABC.*" "DEF.#1"

ダウンロードパッケージを見つけるのは簡単ではありません。自宅でコンパイルするための現在のDebianパッケージ(ArchでもAURでも使用されています)は here で見つかります。

4
jonny

Zshでは、次の行を.zshrc

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

次に、コマンドラインで 実行できます

zcp 'ABC(.*)' 'DEF$1'

または単に

zcp -W ABC.* DEF.*

別のシェルで、zshがインストールされている限り:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

あなたはこれを行うことができます:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done
1
Sara Fauzia