Cygwinの基礎の基礎

# Cygwin

コマンド苦手が時々使うCygwinのコマンドとサンプル。

## はじめに
[Cygwin](https://www.cygwin.com/)とはWindows上でUNIXのコマンドを使えるようにするツールである。
（もしかすると今はPower Shellでも同等のことができるのかもしれないが、Power Shellは試してない。）

CygwinはCUI、つまり文字でPCを操作するインタフェースだが、基本的な考え方はGUIと変わらない。現在開いているディレクトリがあり、そこから目的のディレクトリに移動して、ファイルを開いて作業をする。もちろん、GUI同様に、現在開いているディレクトリから移動せずに作業もできる。

## 準備
### インストール
Cygwin Installationのsetup.exeをダウンロードしてインストール。インストール後は、スタートメニューの [Cygwin] - [Cygwin Bash Shell] から起動。

### 設定
Cygwinディレクトリのルートは「cygdrive」だが、設定で「cygdrive」を入力しなくてよいように変更可能。
C:\cygwin\etc\fstab の5行あたりを以下のように変更する。

変更前: `# none /cygdrive cygdrive binary,posix=0,user 0 0`
変更後: `none / cygdrive binary,posix=0,user 0 0`

上記の変更をすると、`cd /cygdrive/c/xampp/`ではなく`cd /c/xampp/`でOKになる。

## 基本的なコマンド
| コマンド | 挙動 | 例 |
|:-----|:----|:------|
| cd | ディレクトリ移動 | `cd /c/xampp/` |
| exit | 終了 | `exit` |
| ls | 現在のディレクトリ以下を検索 | `ls */image/` |
| find | 検索。「-o」で条件をつなげられる。 | `find . -name '*.html'` |
| grep | 正規表現を使用した検索。「-i」で大文字小文字区別しない。「-L」でその文字を含まない。 | `grep -i 'utf-8' index.html` | 
| wc | カウント。「wc -l」で行数を数える。 | `wc -l` |
| > | 結果をファイルに出力 (同名ファイルがあれば上書き)。他のコマンドと合わせて使う。 | `ls > foo.txt` |
| >> | 結果をファイルに出力 (同名ファイルがあれば追加)。他のコマンドと合わせて使う。 | `ls >> foo.txt` |
| &#x7C; | 結果を別コマンドに渡す。 | ls &#x7C; wc -l |

## 組み合わせ
### HTMLファイルの一覧を作成
```bash
$ find . -name "*.html" > ../list.txt
```

### ファイルの一覧を作成
「dirA」ディレクトリを除外し、全ファイル一覧を作成する場合。

```bash
$ find . -type d -name dirA -prune -o -print > ../list.txt
```

### 拡張子一覧を作成
```bash
$ find . -type f | while read i
> do
> echo ${i##*.}
> done | sort | uniq > ../list.txt
```

### 「gtm.js」という文字列が入っていないHTMLファイル一覧を作成
```bash
$ find . -name '*.html' | while read i
> do grep -L 'gtm.js' $i
> done > ../list.txt
```

### Shift_JISのHTMLファイル数をとる
```bash
$ find . -name '*.html' | while read i
> do nkf -g $i
> done | grep -i shift_jis | wc -l
```

###ディレクトリ内の差分をとる
「dirA/subDir/」「dirB/subDir/」ディレクトリ除く。

```bash
$ diff -qr dirA dirB --exclude=subDir > ../list.txt
```

### SVN管理されているバックアップファイルと思われるファイルを削除
拡張子をいくつか決め打ち + 「xxx.拡張子.xxx」というファイル名の場合。確実にバックアップという保証はないのでコミット前に精査が必要。

```bash
$ find \( -name '*.html.*' -o -name '*.css.*' -o -name '*.js.*' -o -name '*.gif.*' -o -name '*.jpe?g.*' -o -name '*.png.*' \) | while read i
> do svn delete $i
> done
```

「拡張子以降に数字が入っている」場合。確実にバックアップという保証はないのでコミット前に精査が必要。上のよりは精度が高い。

```bash
$ find -regex '.*\..+?\.[A-Za-z_]*[0-9]+[A-Za-z_]*' | while read i
> do svn delete $i
> done
```

### 改行コードの一覧を表示する
```bash
$ find . -name "*.html" | while read i
> do file $i >> ../list.txt
> done
```

### ディレクトリ内の全HTMLをLF → CR+LFに置換
```bash
$ find . -name "*.html" | xargs unix2dos
```

### ディレクトリ内の全HTMLをUTF-8に置換
```bash
$ find . -name '*.html' | while read i
> do nkf -w --overwrite $i
> done
```

### 同じファイルを大量にコピー
作りたいファイル名の一覧 output.txt を読み込んで _template.html を元に複製。output.txt は、1行 = 1ファイル名。

```bash
$ cat output.txt | while read i
> do
> cp -f ./_template.html $i
> done
```

### 特定の拡張子のファイルを別ディレクトリにコピー
「dirA」ディレクトリ以下からPDFファイルを見つけ出し、階層構造は保ったまま「dirB」ディレクトリ配下にコピー。

```bash
$ find dirA -name '*.pdf' | while read i
> do
> mkdir -p dirB/`dirname $i`
> cp $i dirB/`dirname $i`
> done
```

階層構造は以下のようなものを想定。

```
dirA
├ aaa
│ ├ 1.pdf
│ ├ 2.pdf
│ └ 3.txt
├ bbb
│ ├ 4.pdf
│ ├ 5.txt
```

* `while read i...` はwhile文になり、`>`で繰り返す内容を記述できる。
    * `$i`には`find`の検索結果が順に入る。
    * 上記のような構造のとき、`$i`は「aaa/1.pdf」「aaa/2.pdf」「bbb/4.pdf」になる。
* `cp` はディレクトリが存在しないとエラーになるため、コピー先のディレクトリを`mkdir`で作成してから `cp`。
* 作成するディレクトリ名は`dirname`で取得する。