git, cd, su, cat, diff, vim...-(ハイフン)でできること@コマンドライン

こんにちは。
今年の秋からHHKB Pro2 type-sと木製パームレストを使い始めたら肩こりが完全に解消された@ryosukesです。
この記事は[ベーシック](https://basicinc.jp/)のAdvent Calendar 2016の14日目の記事になります。早速始めていきます。

コマンドラインでハイフンを使うと言ったら、思いつくのはどんなときでしょうか。
90%以上の方は、きっとコマンドにオプションを追加するときでしょう。
私も例に漏れずオプションで使うことがほとんどです。

が、他にも使えるタイミングがいくつかあります。
そこでどんなタイミングで使えるのか少し調べてまとめてみました。
(最後にPOSIXとGNUについて軽く触れますが深くは触れないことにします)

# 目次
- [git、cd、suでハイフンを引数に渡すと…](#gitcdsu)
- [cat, diff, vim, wgetでハイフンを引数に渡すと…](#catdiffwget)
- [ハイフンから始まるファイルの扱い](#starthyphen)
- [オプションとしてのハイフンの仕様](#option)

# <a id='gitcdsu'>git、cd、suでハイフンを引数に渡すと…</a>
作業が捗ることがあります。見ていきましょう。

## git
 - `$ git -`
 `Unknown option` となり何も起きません。。使えるのは以下のような他のgitコマンド実行時です。

 - `$ git checkout -`
 一つ前の作業ブランチに戻る事ができます。
 作業途中で差し込みタスクが入った場合など、僕は以下のような感じで上記コマンドを使用して作業しています。

```sh
# 作業途中の内容を一時的に退避
$ git stash 
# 適当にブランチ切る
$ git checkout -b hoge upstream/develop
# 差し込み対応する
$ ...
# 対応完了後元のブランチに戻る
$ git checkout -
# 退避した内容を戻す
$ git stash pop
```
 - `$ git merge -`
 直前にいたブランチを現在のブランチにマージすることができます。
 個人的にはあまり使いませんが、個人開発時などにブランチを分けて作業したい場合は良いかもしれません。

 - `$ git checkout -- hoge.txt`
 上記のコマンドと似ていますが、ハイフンを続けた後に引数でファイルを指定しています。
 何か編集作業を行った際、`$ git status` を実行すると`(use "git checkout -- <file>..." to discard changes in working directory)`とコメントも出るのでだいたいの方がご存知かと思いますが、指定したファイルのみを編集前に巻き戻すことができます。

## cd
 - `$ cd -`  
 直前にいたディレクトリに戻ることができます。  
 間違って移動した際や、調べ物をしている際などに使うことが多いです。

## su
 - `$ su - hoge`  
 hogeユーザーになり、hogeユーザーのホームディレクトリに移動します。
 この時、ディレクトリが移動するだけではなく、hogeユーザーの環境設定がそのまま引き継がれます。そのため、hogeユーザーでしかパスが通っていないコマンドも扱えるようになります。
 (もしハイフンがない`$ su hoge`を実行した場合、hogeユーザーになりますが実行したディレクトリに残ります)

# <a id='catdiffwget'>cat, diff, vim, wgetでハイフンを引数に渡すと…</a>
標準入力または出力として認識されます。
ワンライナーでごにょごにょしたいとき便利ですね。

## cat

```sh
$ cat -
```

とコマンドを叩くと、入力ができるようになり入力したものがそのまま出力されます。

```sh
$ cat -
hoge(←入力)
hoge(←出力される)
```

これをパイプを使って応用すると、
「piyo」とだけ書かれたpiyo.txtと「fugafuga」と書かれたfuga.txtをつなげて標準出力で表示できるようになります。

```sh
$ cat piyo.txt | cat - fuga.txt
piyo
fugafuga
```

## diff

`aaabbb`とだけ書かれたtest.txtファイルをsedコマンドで置換、
その後`cccddd`とだけ書かれたtest2.txtとの差分を表示！
みたいなことがワンライナーでできるように。

```sh
$ sed "s/ab/cd/g" test.txt | diff - test2.txt
1c1
< aacdbb
---
> cccddd
```

## vim

vim, lessコマンドでもハイフンが使えます。
diffコマンドなどで表示された差分でハイライトしたい場合に便利だそうです。
git diffなどでも使えるそう(vimmerではないのでまったく使わず…)

なおlessを使えばハイフンすら不要なので代替できるかと思いましたがうまくいかず。
[lessでソースコードに色をつける（Mac OS編）](http://ymotongpoo.hatenablog.com/entry/20111110/1320887575)を参考に色がつけられるようにしているのですが、パイプで渡すと環境変数が読み込まれていないようでした。
このあたり詳しい方いらっしゃったらご教示いただけると嬉しいです。

## wget
wgetコマンドは-O (--output-document=) オプションでファイル名を指定でき、ファイル名にハイフンを渡すとそのまま標準出力へ出てきます。

```sh
$ wget http://www.example.com/ --output-document=-
```

さらにパイプを繋げてgrepすることで情報が抽出できます。
このあたり[ハイフンを使った便利な標準入出力指定でのコマンドライン](http://qiita.com/bami3/items/d67152d19aa8ac2d47de)という記事が非常に参考になりました。

■ 参考
[catの-(ハイフン)オプションを使う](http://twinbird-htn.hatenablog.com/entry/2016/06/03/125239)
[ハイフンを使った便利な標準入出力指定でのコマンドライン](http://qiita.com/bami3/items/d67152d19aa8ac2d47de)


# <a id='starthyphen'>ハイフンから始まるファイルの扱い</a>
ここからはおまけみたいなものです。

ハイフンから始まるファイルが神のいたずらによって作られてしまって、
消せなくてググったという方、意外といらっしゃるのではないでしょうか

```sh
$ rm -hoge.txt
```

これ、オプションとして認識されてしまって消せないんですよね。
この時の対処方法は２つあります。

```sh
# その1
$ rm -- -hoge.txt
# その2
$ rm ./-hoge.txt
```

ちなみに、あえてハイフンから始まるファイルをgit addしたい場合やmvしたい場合、
同様にハイフンを２つ並べて上げれば操作可能です。

```sh
$ mv -- -hoge.txt piyo/
$ git add -- -hoge.txt
```

`touch`などでハイフンから始まるファイルを作ろうとしても、だいたいオプションとして認識され作成に失敗するのでレアケースかと思いますが、
ハイフンから始まるファイルはハイフン２つを与えてやれば、大方対応できそうですね。

# <a id='option'>オプションとしてのハイフンの仕様</a>
コマンドラインのオプションで、ハイフンが１つのものと２つものがあります。
この違いは何でしょう。

ざっくり動作の部分だけ説明すると、
1つの場合複数のオプションをまとめて指定でき、
2つの場合長くてわかりやすいオプション名で指定できます。

```sh
# 1つの場合
$ ls -aF
# 2つの場合
$ ls --all --classify
```

このコマンドオプションの定義に関しては、POSIXとGNUという異なった仕様が存在し、
使用しているOSによって使えるオプションも異なってきます。
詳しいことは割愛しますが、どんなオプションが使えるかは必ず`man`コマンドや`-h/--help`などで確認するのが良いです。
Linuxで使えるけどMacでは使えないとかままあります。

POSIXとGNUに関してですが、下記記事が分かりやすかったです。
[コマンドラインプログラムにおける引数、オプションなどの標準仕様](http://yohshiy.blog.fc2.com/blog-entry-260.html)

また下記の記事でもPOSIX互換環境について触れていて、なかなか面白かったです。
昔WindowsにCygwin入れて少しだけ使ったけれど、すぐUbuntu入れたのを思い出しました。
[技術屋にMac使いが多い理由ってなに？](https://cpplover.blogspot.jp/2013/11/mac.html)

以上です。