web-dev-qa-db-ja.com

構文を理解しようとして、ターミナルlinuxmintを使用してディレクトリ内のすべての画像を見つけてコピーします

OS Linux Mint

タイトルが言うように、最終的にディレクトリ内のすべての画像を見つけてコピーしたいと思います。

私が見つけた:

ディレクトリ内のすべてのjpg(またはJPG)ファイルを検索し、それらをフォルダ/ home/joachim/neu2:にコピーします。

find . -iname \*.jpg -print0 | xargs -I{} -0 cp -v {} /home/joachim/neu2

そして

ディレクトリ内のすべての画像ファイルを検索:

find . -name '*' -exec file {} \; | grep -o -P '^.+: \w+ image' 

私の問題はまず第一に、私は構文を本当に理解していません。誰かがコードを説明できますか?

そして第二に、誰かが私が望むことをするコードを生成するために2つのコードを接続することができます;)

よろしくお願いします!

13
newandlost

まず、パイプ「|」がリンクコマンドは、最初の出力を引数として2番目の出力にパイプします。 2つのシェルコードは両方ともfindコマンドの出力を他のコマンド(grepとxargs)にパイプします。これらのコマンドを次々に見ていきましょう。

最初のコマンド:find

findは、「ディレクトリ階層内のファイルを検索する」プログラムです(これは、findのマニュアルページからの説明です)。構文は(この場合)です

find <search directory> <search pattern> <action>

どちらの場合も、検索ディレクトリはです。 (これが現在のディレクトリです)。現在のディレクトリだけでなく、そのすべてのサブディレクトリ(ディレクトリ階層)も検索することに注意してください。

検索パターンは、オプション-name(名前がこのオプションの引数として指定されたパターンと一致するファイルを検索することを意味します)または-iname(名前と同じですが大文字と小文字を区別します)などを受け入れます。

アクションパターンは、-print0(指定された検索ディレクトリ内の位置を含む正確なファイル名、つまりファイルへの相対パスまたは絶対パスを出力)または-exec(ファイルに対して指定されたコマンドを実行します。コマンドは次のとおりです。 「;」で終わり、「{}」のすべてのインスタンスはファイル名に置き換えられます)。

つまり、最初のシェルコード(最初の部分、パイプの左側)

find . -iname \*.jpg -print0 

現在のディレクトリ階層で「.jpg」で終わるすべてのファイルを検索し、それらのパスと名前を出力します。 2番目(前半)

find . -name '*' -exec file {} \; 

現在のディレクトリ階層内のすべてのファイルを検索して実行します

file <filename>

それらの上に。 Fileは、ファイルタイプを決定して出力する別のコマンドです(詳細については、manページのmanファイルを参照してください)。

2番目のコマンド:xargs

xargsは、「標準入力からコマンドラインを構築して実行する」(man xargs)、つまりxargsにパイプされるfind出力からのコマンドです。この場合、ビルドして実行するコマンドは

cp -v {} /home/joachim/neu2"

オプション-I {}は、置換文字列を定義します。つまり、コマンド内の{}のすべてのインスタンスは、ファイルから取得した入力(つまり、ファイル名)に置き換えられます。オプション-0は、入力項目が空白または改行ではなく、ヌル文字でのみ終了(区切り)されることを定義します。これは、find出力をxargs入力として処理する標準的な方法を使用する場合に必要と思われます。

ビルドされて実行されるコマンドは、もちろんオプション-v(詳細)を指定したcopyコマンドであり、findから取得した各ファイル名をディレクトリにコピーします。

3番目のコマンド:grep

grepは入力をフィルタリングして、特定の出力パターンに一致する行または文字列のみを提供します。オプション-oは、行全体ではなく、一致する文字列のみを出力するようにgrepに指示します(man grepを参照)。-Pは、次のパターンをPerl正規表現パターンとして解釈するように指示します。 Perl正規表現では、^は行の先頭、。+は任意の文字列です。この任意の文字列の後に、コロン、スペース、いくつかの英数字(Perl正規表現では\ w +で示されます)、スペース、および文字列を続ける必要があります。 "画像"。基本的に、このgrepコマンドはファイル出力をフィルタリングして、画像ファイルであるファイル名のみを出力します。 (たとえば、Perl正規表現についてはこちらをご覧ください: http://www.comp.leeds.ac.uk/Perl/matching.html

実際に必要なコマンド

ここで、(1)2番目のShellコマンド(画像ファイルを一覧表示)の出力を取得し、(2)適切な形式に変換し、(3)最初のShellコマンドからxargsコマンドにパイプします。行(次に、必要なコピーコマンドをビルドして実行します)。したがって、今回は2つのパイプを使用した3段階(実際には4段階)のシェルコマンドがあります。問題ない。すでにステージ(1)と(3)があります(ステージ(3)では、入力が出力を見つけられなくなったため、-0オプションを省略する必要があります。改行を項目区切り文字として扱うために必要です)。

ステージ(2)はまだありません。これにはcutコマンドを使用することをお勧めします。 cutは、文字列をpyで変更し、それらを異なるフィールド(元の文字列では区切り文字で区切って)に分割し、再配置できるようにします。区切り文字として「:」を選択し(これにより、grep出力のファイル名が終了します。オプション-d ':')、最初のフィールドのみを指定するように指示します(オプション-f1、essentialls:ファイル名のみを出力します。 「:」の後に続く部分、つまりステージ(2)は次のようになります。

cut -d':' -f1

そして、必要なコマンド全体は次のようになります。

find . -name '*' -exec file {} \; | grep -o -P '^.+: \w+ image' | cut -d':' -f1 | xargs -I{} cp -v {} /home/joachim/neu2

たとえば、ここですべてのマニュアルページを見つけることができることに注意してください: http://www.linuxmanpages.com

22
0range

上記の答えは本当に良いです。ただし、巨大なディレクトリの場合は、さらに時間がかかる可能性があります。あなたがすでにあなたのファイル拡張子を知っているならば、これはそれのより短いバージョンです

 find . -name \*.jpg | cut -d':' -f1 | xargs -I{} cp --parents -v {} ~/testimage/
0
Shahin Khani

私は、同様に機能するawkのみを使用してコマンドを理解しました。

find . -name '*' -exec file {} \; | 
awk '{
    if ($3=="image"){
        print substr($1, 0, length($1)-1);
        system("cp " substr($1, 0, length($1)-1) " /home/joachim/neu2" )
    }   
}'

substr($ 1、0、length($ 1)-1)が必要なのは、最初の列でファイルが名前を返すためです。

0
newandlost