あれとこれ以外のmv

### 概要
「この拡張子とあの拡張子以外のファイル」の抽出を実現し，さらにそれを応用して「この拡張子とあの拡張子以外のファイルを移動させる」ということを実現します．

# はじめに
「あの拡張子をまとめて移動したい」は，次のように簡単に実現できます．

```
$ 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
...
```