mkdir と同時に cd でディレクトリ移動させるには（空白入りディレクトリ名の場合）

`bash` や `zsh` などのシェルで、ディレクトリ作成と同時にディレクトリ移動をしたい場合、一般的に以下のコマンドで可能です。

```bash:ディレクトリを作成後、cd で移動する
mkdir my_dir && cd $_
````

`$_`（ダラー・アンダーバー）は、1つ前の処理の最後のパラメーターを保持している環境変数 "`_`" を展開（変数の中身を返し）ます（この場合 `my_dir`。詳しくは後述）。

しかし、この時**ディレクトリ名にスペースがあると `No such file or directory` エラーが出る**のです。どうしよう。

```shell-session:ディレクトリ作成と同時に移動
$ # スペースなしディレクトリ名で作成と同時に移動（成功）
$ mkdir my_dir && cd $_

$ # スペース付きディレクトリ名で作成と同時に移動（失敗）
$ mkdir "my dir" && cd $_
-bash: cd: my: No such file or directory
```

[「`mkdir` `同時に移動` `cd`」で Qiita 記事をググって](https://www.google.com/search?q=site:qiita.com+mkdir+%E5%90%8C%E6%99%82%E3%81%AB%E7%A7%BB%E5%8B%95+cd)も、ピンポイントに出でこなかったので、自分のググラビリティとして。

## TL; DR <sub><sup>（今北産業）</sup></sub>

> 特殊パラメーター `$_` でスペース入りの値を扱うにはクォート付き（`"$_"`）で使う。

毎回忘れる。

```bash
mkdir "my dir" && cd "$_"
```

```shell-session
$ pwd
/Users/KEINOS/Tests/ls_dir

$ ls -la
total 0
drwxr-xr-x   2 admin  staff    68  2 12 12:28 .
drwxr-xr-x  32 admin  staff  1088  2 12 12:09 ..

$ mkdir "my dir1 as hoge and very long directory name"
$ mkdir "my dir2 as hoge and very long directory name"
$ ls -la
total 0
drwxr-xr-x   4 admin  staff   136  2 12 12:28 .
drwxr-xr-x  32 admin  staff  1088  2 12 12:09 ..
drwxr-xr-x   2 admin  staff    68  2 12 12:28 my dir1 as hoge and very long directory name
drwxr-xr-x   2 admin  staff    68  2 12 12:28 my dir2 as hoge and very long directory name

$ ls my*1* && cd "$_"
$ pwd
/Users/KEINOS/Tests/ls_dir/my dir1 as hoge and very long directory name
```

## TS; DR <sub><sup>（kwsk）</sup></sub>

### 特殊環境変数`_`（アンダーバー、アンダースコア）の挙動について

`bash` や `zsh` などのシェルには、"`_`"（アンダーバー、アンダースコア）という「特殊パラメーター」（特殊環境変数）があります。

現在の設定値を確認するには `env` コマンドもしくは `echo $_` で確認することができます。

この変数には「１つ前のコマンド操作のコマンド内容をスペースに区切り、最後の区切りがパース（処理）された値」が代入されています。

これを応用するとディレクトリ作成と同時に移動などに活用できます。

```
$ mkdir my_very_long_directory_name && cd $_
```

> 🐒 &nbsp; <font color="darkorange">**Alpine Linux の `ash` など、特殊パラメーターが使えないシェルもある**</font>ので、[Docker](https://ja.wikipedia.org/wiki/Docker) や [CI](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) などのスクリプトで使う場合は注意します。

### スペース付きディレクトリ名に注意

シェルでスペース付きのパスを扱う場合はクォートするのが常です。この特殊パラメーター `$_`（ダラー・アンダーバー）も同様に `"$_"` のように[引用符](https://ja.wikipedia.org/wiki/%E5%BC%95%E7%94%A8%E7%AC%A6)（ダブルクォーテーション）でクォートして使います。

クォートしないとスペース入りのディレクトリ名で `No such file or directory` エラーが出るので注意します。（←俺

```shell-session:一般エラー表示
$ mkdir "my dir" && cd $_
-bash: cd: my: No such file or directory
```

```shell-session:日本語エラー表示
$ mkdir "my dir" && cd $_
-bash: cd: my: そのようなファイルやディレクトリはありません
```

### 特殊パラメーター（スペシャルパラメーター） `$_` について

> **`_`**
> (`$_`, an underscore.) At shell startup, set to the absolute pathname used to invoke the shell or shell script being executed as passed in the environment or argument list. Subsequently, expands to the last argument to the previous simple command executed in the foreground, after expansion. Also set to the full pathname used to invoke each command executed and placed in the environment exported to that command. When checking mail, this parameter holds the name of the mail file.
> 
> （[Bash のスペシャル・パラメータ `$_` に関するリファレンス](http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters) | bash | manual @ GNU.org より）

以下、筆者訳

> **`_`とは**
> （`$_`、アンダースコア、アンダーバー）シェルの起動時に、シェルを呼び出すために参照する絶対パス名、または環境設定ファイルで指定され実行されたシェル・スクリプト名、もしくは引数のリストが設定されます。 その後は、直前にフォアグラウンドで実行された単純なコマンドがあると、最後の引数が展開されます。また、実行されたコマンドによりエクスポートされ、環境（変数などの空間）に置かれた各コマンドを呼び出すために使用される絶対パス名にも設定されます。 メールのチェック時は、このパラメータはメールのファイル名前を保持します。

自分で訳しておいて何ですが、よく意味がわかりません。

英文自体がこねくり回されていて、よく意味がわからんのです。しかし、言わんとしているのは、以下のことだと思います。

1. 初期値には実行コマンドを検索するパスの環境変数（つまり文字列 `PATH`）が設定されている。
2. メール・コマンドを実行すると、最後に開いたメールのファイル名がセットされる。
3. 呼び出し直前にコマンドが実行されていた場合、その**コマンドの引数を展開した最後の値**がセットされる。

ここで言う<strong>「展開」とは、直前のコマンド文をスペース区切りに分け、最後の要素を実行すること</strong>と思われ、その結果が "`_`" という変数にセットされます。使い方もシェルの変数と同じです。変数を使う（展開する）時は `$` 記号を付け、改行やスペースを扱うときは "`$_`" とクォートします。

しかし、その展開方法にも、まだ謎がある（理解できない）部分があります。

例えば ​@7of9​さんの[記事](https://qiita.com/7of9/items/ebfaa2367fe3f9e19e1b)で、アスタリスク（`*`）を使った場合の面白い挙動がありました。上記説明文にある `mail` コマンドの挙動の応用技でしょうか、**`ls` コマンドで表示された最後のファイル名が取得できます**。

```shell-session
$ ls -l
sample1.md
sample2.md
$ echo $_
-l

$ ls *.md
sample1.md
sample2.md
$ echo $_
sample2.md
```
- 「[linux command >多数のファイルから一つだけ（最後のファイルだけ）を開く手順 > `$_`使用 > ls log.* してから `vi $_` (または`less $_`)](https://qiita.com/7of9/items/ebfaa2367fe3f9e19e1b)」@ Qiita

## 展開の事例

このように、まだ謎が多く動作もわかりづらいコマンドの１つで、使い始めると妙に便利で、かなりの頻度で利用するようになります。

下記の「展開例」を、シェルの変数の動きを想像しながら見ていくと、うっすらと見える気がします。（← わかってない）

<details><summary>展開例</summary><div>

```shell-session:直前のコマンドの引数に注目
$ echo hoge
hoge
$ echo $_
hoge

$ echo hoge fuga
hoge fuga
$ echo $_
fuga

$ echo "hoge fuga"
hoge fuga
$ echo $_
hoge fuga
$ echo $_
fuga
echo $ echo "$_"
fuga

$ echo "hoge fuga"
hoge fuga
$ echo "$_"
hoge fuga
$ echo "$_"
hoge fuga

$ ls -la
...（省略）
$ echo $_
-la   ← コマンドの実行結果でなくコマンドの引数が展開されて最後がセットされていることに注目

$ # ls の実行結果の最後の行を取得
$ ls *.md | tail -1
sample.md
$ ls *.md && echo $_
sample.md

$ # オプションは効かない（更新日順の -t オプションを使った場合）
$ ls -t *.md | tail -1
old_sample.md
$ ls -t *.md  && echo $_
sample.md ← つまり実行結果の最後ではないということ
```
</div></details>

### 動作確認済み環境

- macOS Mojave（OSX 10.14.3）
    - GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
- macOS HighSierra（OSX 10.13.6）
    - GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
- Raspbian GNU/Linux 8（Jessie）
    - GNU bash, バージョン 4.3.30(1)-release (arm-unknown-linux-gnueabihf)

### あわせて読みたい

- 「[mkdirとcdを同時に](https://qiita.com/akokubu/items/d577d0d8ccc6464286c1)」@ Qiita
- 「[ターミナルの作業が捗るかもな小技５つ](https://qiita.com/simeji/items/cae94349a2ae02d3204d)」@ Qiita
- [公式 Bash リファレンス](http://www.gnu.org/software/bash/manual/bashref.html)@ GNU.org