概要
「この拡張子とあの拡張子以外のファイル」の抽出を実現し,さらにそれを応用して「この拡張子とあの拡張子以外のファイルを移動させる」ということを実現します.
はじめに
「あの拡張子をまとめて移動したい」は,次のように簡単に実現できます.
$ mv *.txt ~/Desktop
それでは「あの拡張子以外」のファイルの移動は,どうやって実現するのでしょうか?また,「この拡張子とあの拡張子以外」のファイルの移動は,どうやって実現するのでしょうか?これを実現することがこの記事の目的です.
注意点
- grepやgawk, gsedは正規表現が使えるが,findでは-regexを使わなければ正規表現は使えません.
- mv(BSD Jul/9/2002)ではワイルドカード"*"(任意の文字列)しか使えません.
- 「あの拡張子以外」の中には設定ファイルなどの隠しファイルも含まれてしまうので,必ずそれを除外しなければいけません.
- 「あの拡張子以外」の中には隠しディレクトリや恒等写像ディレクトリなども含まれてしまうので,ファイルに限って行うようにします.おそらく何も起こらないと思いますが,意図しない動きを想定してあらかじめ対策しておきます.
環境
実行環境は,macOS Sierra 10.12.3のTerminal.appです.Linuxでも同じようにできると思います.
$ echo $SHELL
/bin/bash
$ ls .
11.awk from1945to1961.php
chron.sh from1962to1973.php
event.txt from1974to1989.php
factor.png memo.txt
from1894to1918.php report.pdf
from1920to1944.php year.txt
ファイルの選択抽出
あのファイルはどこ?
findコマンドでEmacsの設定ファイル".eamcs"を探します.
$ find / -name '.emacs'
find: /.DocumentRevisions-V100: Permission denied
find: /.fseventsd: Permission denied
find: /.Spotlight-V100: Permission denied
find: /.Trashes: Permission denied
...
/Users/user/.emacs
/Users/user/Dropbox/html/others/offset/emacs/linux/.emacs
/Users/user/OneDrive/offset/emacs/linux/.emacs
/Users/user/OneDrive/offset/emacs/win/.emacs
このディレクトリのあの拡張子のファイルを抽出する
カレントディレクトリの中だけに存在する".php"のファイルを抽出します.
$ find . -type file -maxdepth 1 | grep '.*\.php'
./from1894to1918.php
./from1920to1944.php
./from1945to1961.php
./from1962to1973.php
./from1974to1989.php
または,
$ find . -type file -maxdepth 1 -regex '.*\.php'
./from1894to1918.php
./from1920to1944.php
./from1945to1961.php
./from1962to1973.php
./from1974to1989.php
あれかこれか?
カレントディレクトリの中だけに存在する".php"のファイル,もしくは".txt"のファイルを抽出します.
$ find . -type file -maxdepth 1 | grep '.*\.\(php\|txt\)'
./event.txt
./from1894to1918.php
./from1920to1944.php
./from1945to1961.php
./from1962to1973.php
./from1974to1989.php
./memo.txt
./year.txt
あれ以外
カレントディレクトリの中だけに存在する".php"以外のファイルを抽出します.
$ find . -not -name '*.php' -type file -maxdepth 1
./.DS_Store
./11.awk
./chron.sh
./event.txt
./factor.png
./memo.txt
./report.pdf
./year.txt
または,
$ find . -type file -maxdepth 1 | grep -ve '.*\.php'
./.DS_Store
./11.awk
./chron.sh
./event.txt
./factor.png
./memo.txt
./report.pdf
./year.txt
あれとこれ以外
カレントディレクトリの中だけに存在する".php"と".txt"以外のファイルを抽出します.
$ find . -not -name '*.php' -a -not -name '*.txt' -type file -maxdepth 1
./.DS_Store
./11.awk
./chron.sh
./factor.png
./report.pdf
または,
$ find . -type file -maxdepth 1 | grep -ve '.*\.php' | grep -ve '.*\.txt'
./.DS_Store
./11.awk
./chron.sh
./factor.png
./report.pdf
隠しファイルは抽出しない
ドット'.'で始まる隠しファイルまで移動させないようにします.次の例では,カレントディレクトリの中だけに存在する".php"以外のファイル(ただし,隠しファイルを除く)を抽出します.
$ find . -not -name '*.php' -type file -maxdepth 1 | gsed -e '/\.\/\./d'
./11.awk
./chron.sh
./event.txt
./factor.png
./memo.txt
./report.pdf
./year.txt
ファイルの選択抽出の応用
移動用のディレクトリを作ります
$ mkdir tmp
「あの拡張子以外」の移動
カラクリとしては,まず抽出して,それをxargsで所定の場所に渡し,mvを実行します.具体的に,まずカレントディレクトリの中だけに存在する".php"以外のファイル(ただし,隠しファイルを除く)を抽出します.そして,それをxargsでmvの第1引数に渡し,mvを実行します.
$ find . -not -name '*.php' -type file -maxdepth 1 \
> | gsed -e '/\.\/\./d' | xargs -I {} mv {} tmp/
「この拡張子とあの拡張子以外」の移動
具体的に,まずカレントディレクトリの中だけに存在する".php"と".txt"以外のファイル(ただし,隠しファイルを除く)を抽出します.そして,それをxargsでmvの第1引数に渡し,mvを実行します.
$ find . -not -name '*.php' -a -not -name '*.txt' -type file -maxdepth 1 \
> | gsed -e '/\.\/\./d' | xargs -I {} mv {} tmp/
付録A:プロセスの探索の工夫
"./"を消す
"./"が邪魔であれば、次のようにgawkを使って消すことができます.
$ find . -type file | grep '.*\.php' | gawk -F '/' '{print $NF}'
from1894to1918.php
from1920to1944.php
from1945to1961.php
from1962to1973.php
from1974to1989.php
プロセスのコマンド名はルートパスで表される
$ ps axo command | gawk -F '/' '{print $NF}'
ルートパスは見にくいので実行ファイルのみで表す
psコマンドのcommandはルートパスで表示されるので,横幅が狭いシェルやルートパスまで必要のないときは,次のように省略します.
$ ps axo command | gawk '{print $1}' | gawk -F '/' '{print $NF}'
付録B:エラーメッセージを出力させない
標準エラーを/dev/nullにリダイレクトすると,エラーメッセージがbash上に出力されません.
$ find / -name '*.php' 2> /dev/null
animals.php
main.php
index.php
...