

ある特定のファイルの名前を記したテキストファイル(1)と、実際の（大量の)ファイルが格納されているディレクトリ(2)があります。

(1)に記載されているファイルの名前と一致するファイルのみを(2)から抽出してきたいです。  
linuxでどのようにコマンドを打てばこれが実行可能でしょうか。ぜひご教授ください。日本語がわかりにくくてすみません、よろしくお願い致します。

例としては  
`filenames.txt`

[code]

    file1    
    file3
    file5
    file8
    file10
    file11
    
[/code]

`/usr/local/actualfilesdir/`

[code]

    file1 file7
    file2 file8
    file3 file9
    file4 file10
    file5 file11
    file6 file12
    
    
[/code]

とあった場合 `filenames.txt`を参照して`/actualfilesdir/`から

[code]

    file1    
    file3
    file5
    file8
    file10
    file11
    
[/code]

のみを抽出してきたい、ということになります。


CC BY-SA 4.0
2019-09-03T08:48:17.903
57804
2019-09-19T10:11:17.370
2019-09-19T10:11:17.370
32986
35702
question
linux
linuxでファイルを比較し一致する部分を抽出する


自分だったら、

  * ファイル名に改行は含まれない。
  * ファイル名にダブルクォーテーションは含まれない。
  * `filenames.txt` に書かれているファイル数のほうが `actualfilesdir` 下にあるファイル数より少ない。

という条件下であれば、シェルスクリプトで以下のように後続処理へ続けます。

[code]

    # たとえば抽出後のファイル名を echo するなら
    cat filenames.txt | xargs -I {} sh -c '[ -e "/usr/local/actualfilesdir/{}" ] && echo {}'
    
[/code]

ただ後続処理が複雑なのであれば、シェルスクリプトではなく他のプログラミング言語でプログラムを書きます。シェルスクリプトで[複雑な処理](https://google.github.io/styleguide/shell.xml?showone=When_to_use_Shell#When_to_use_Shell)を書くとメンテナンスしづらいと思っているためです。


CC BY-SA 4.0
2019-09-03T09:35:00.757
57805
2019-09-03T09:35:00.757
19110
57804
answer


本質的には、質問者様のやりたいことは、
「ファイルに記述された(ディレクトリ部分を含まない)ファイル名の一覧」と、実際に特定ディレクトリに含まれているファイルたちのファイル名の、共通部分の抽出である、と理解しました。

これを実装するにあたって、 @nekketsuuu さんもおっしゃっていますが、ある程度のファイル名についての前提が必要です。具体的には、

  * ファイル名に改行は含まれない

が必要であると思っています。

逆に、これが達成できているのであるならば、 unix 系で「行の共通部分」を計算するイディオムである、 `grep -Fxf`
が使えると思っています。具体的には:

[code]

    ( cd /usr/local/actualfilesdir/ && ls -1 ) | grep -Fxf filenames.txt
    
[/code]

上記によって、「共通するファイル名一覧」が得られますので、必要であれば、これに対してさらに for 文などを回すことで、様々な処理が行えると思っています。


CC BY-SA 4.0
2019-09-04T03:37:03.073
57828
2019-09-04T03:37:03.073
754
57804
answer


こんなイメージでしょうか？

[code]

    $ pwd
    /tmp/work
    
    $ ll
    total 28K
    -rw-rw-r-- 1 genzouw wheel  2  9 19 08:48 1.txt
    -rw-rw-r-- 1 genzouw wheel  2  9 19 08:48 2.txt
    -rw-rw-r-- 1 genzouw wheel  2  9 19 08:48 3.txt
    -rw-rw-r-- 1 genzouw wheel  2  9 19 08:48 4.txt
    -rw-rw-r-- 1 genzouw wheel  2  9 19 08:48 5.txt
    -rw-rw-r-- 1 genzouw wheel  5  9 19 08:50 11.txt
    -rw-rw-r-- 1 genzouw wheel 18  9 19 08:48 list.txt
    
    $ cat list.txt
    1.txt
    3.txt
    5.txt
    
    $ ls /tmp/work | grep -w -f list.txt
    1.txt
    3.txt
    5.txt
    
[/code]


CC BY-SA 4.0
2019-09-18T23:51:28.583
59142
2019-09-18T23:51:28.583
34583
57804
answer


効率の善し悪しはともかく、別解:

[code]

    $ { cat filenames.txt; ls /usr/local/actualfilesdir; } |sort |uniq -d
    
[/code]

その2 (`ls` の `No such file or directory` 以外のエラーが隠れるのがいまひとつ):

[code]

    $ (cd /usr/local/actualfilesdir && xargs ls -1 2>/dev/null) <filenames.txt
    
[/code]

前提条件:

  * ファイル名に改行を含まない。
  * `filenames.txt` は重複する名前を含まない。


CC BY-SA 4.0
2019-09-19T04:27:31.657
59152
2019-09-19T04:27:31.657
3061
57804
answer