Linuxコマンド or Bashの備忘録


# 汎用コマンド

## ssh

### リモート先のファイルの存在チェック

```bash
REMOTE_FILE="foo.txt"
if ssh localhost "[[ -e ${REMOTE_FILE} ]]" ; then
    echo "ファイルあり"
else
    echo "ファイルなし"
fi
```

## grep

### 終了ステータス
該当行が見つからないときは終了ステータスが1になります。`set -e`でエラーがあったら止まる状態にしている場合は、注意が必要です。

https://linuxjm.osdn.jp/html/GNU_grep/man1/grep.1.html


## find

### ファイル名だけ表示

```
$ find . -printf "%f\n"
```


## xargs

[Man page of XARGS](https://linuxjm.osdn.jp/html/GNU_findutils/man1/xargs.1.html)
[xargsコマンドで覚えておきたい使い方・組み合わせ7個(+1個)](https://orebibou.com/2015/07/%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AA%E3%82%89%E8%A6%9A%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E3%80%8Exargs%E3%80%8F/)
[xargsのオプション無し、-Iオプション、-0オプションの挙動に関する勘違い](https://qiita.com/takc923/items/da1c32f3a622dc1c5489)

### デリミタを改行にする

findコマンドで見つかったファイルが半角スペースを含む場合は、xargsコマンドのデリミタを改行にする必要があります。

```
$ find . -name "*.txt" | xargs -d "\n"
```
NULL文字を区切りにして対応することもできます。

```
$ find . -type f -print0 | xargs --null md5sum
```

### 個別のファイルにリダイレクト
* `sh -c`：で引数に渡された文字列を、コマンドを実行する
* `xargs -t` : 実行する前に、コマンドラインを標準エラー出力に表示する。

```shell-session
$ ls *.png
a.png  b.png  c.png
$ find . -name "*.png" | xargs -t -I{} sh -c "identify  -verbose {} > {}.identify"
sh -c identify  -verbose ./a.png > ./a.png.identify
sh -c identify  -verbose ./b.png > ./b.png.identify
sh -c identify  -verbose ./c.png > ./c.png.identify
$ ls *.identify
a.png.identify b.png.identify c.png.identify
```

http://d.hatena.ne.jp/iww/20141219/xargs

### 改行コードを入れてファイルを連結する
1行1ファイルのJOSN（改行コードなし）を連結して、JSON Linesを生成する。

```
$ find -type f -name "*.json" | xargs -I{} sh -c "cat {}; echo ''" > ../lines.json
```


`find`対象のプロジェクトに`lines.json`を出力すると、「入力ファイルと出力ファイルが同じです」という警告が出る。

### 応用：grepで抽出したファイルを削除する
```
$ find . -type f -name "*.json" -print0 | xargs -0 grep --files-with-matches 'foo'  |  xargs  rm
```

## ls

### ディレクトリ内のファイル数をカウント

```shell-session
$ ls -U1 | wc -l
```

`-U`でソートしなくなるので、速くなる。
https://qiita.com/stc1988/items/e3a1d7dccafe4ab573fa

## date

### dateコマンドの1か月前や1か月後は30日で計算しているだけ
https://data-memorandum.blogspot.com/2015/09/linux-date.html

```
# 2020-03-31の1か月後は2020-04
$ date --date "2020-03-30 1 month" +%Y-%m
2020-04

# 2020-03-31の1か月後は2020-05？
$ date --date "2020-03-31 1 month" +%Y-%m
2020-05

```

## diff

### ディレクトリ構成のみの比較（ファイルの中身は比較しない）

```shell-session
$ diff <(ls -1 dir1) <(ls -1 dir2)
```

## rsync

### ssh経由でリモート先にコピー

```shell-session
# `ssh remotehost`で接続できるよう、あらかじめ`.ssh/config`に設定してある状態
$ rsync -auv -e "ssh" src remotehost:~/dest
```

* `-u` : 転送先に既にファイルが存在し、転送先のタイムスタンプの方が新しい場合は転送しない
* `-v` : 詳細情報を表示

https://hydrocul.github.io/wiki/commands/rsync.html

## tmux

### プロンプトの色が表示されるようにする
tmuxを利用しているときも、プロンプトに色（環境変数`PS1`の設定）を付けるため、`.bashrc`の`force_color_prompt=yes`部分のコメントを外す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/198e62b2-5c1d-66d0-981e-38d7c8fcc6ef.png)

https://unix.stackexchange.com/questions/360545/tmux-not-colorizing-ps1-prompt/493472

### 履歴の上限を増加する

```
set -g history-limit 10000
```

https://wiki.archlinux.jp/index.php/Tmux

## rename

### 再帰的にファイル名の先頭に`prefix-`を付ける

```
$ find . -name "*.csv" | xargs rename 's/([^\/]*)$/prefix-$1/'
```

## sed

### 特定のキーワードを見つけた行から、末尾までを削除する
```txt:foo.txt
AAA
BBB
CCC
DDD
```

```
$ sed "/BBB/q" foo.txt | sed -e '$d'
```



# システム管理系のコマンド

## crontab

### crontabで実行するスクリプトでは、bashrcを読み込まない方がよい
対話的なシェルでないと、bashrcの読み込み途中でreturnされてしまうため
https://qiita.com/takaram/items/17e739e9b7d4d7b6de42

### パーセント記号はエスケープする

```
# 動かない
# 00 04 * * * TODAY=$(date "+%Y-%m-%d"); echo ${TODAY} > ~/log/${TODAY}.txt 2>&1
# 動く
00 04 * * * TODAY=$(date "+\%Y-\%m-\%d"); echo ${TODAY} > ~/log/${TODAY}.txt 2>&1
```

https://blog.manabusakai.com/2013/05/crontab-escape-percent/

### cronの実行ログはjournalctlコマンドで確認する

```
sudo journalctl --follow --unit cron
-- Logs begin at Thu 2019-05-30 11:01:44 JST. --
...snip
 6月 22 23:03:01 pinkumohikan.com CRON[2080]: (pinkumohikan) CMD (echo 1)
...snip
```


https://blog.pinkumohikan.com/entry/use-journalctl-for-view-cron-execution-log

### crontabのデフォルトシェルはshなので、sourceコマンドは使えない
https://cm3.hateblo.jp/entry/2016/08/13/064842

## ssh

* `-i`：秘密鍵のファイルを指定
* `-Y`: X11 ForwardingでGUI操作（Enables trusted X11 forwarding.)
    - `-X`と`-Y`の違い：https://changineer.info/network/terminal_software/cygwin_xserver.html#ssh_-X-Y

### 秘密鍵を指定したときに「Permissions ... are too open」というエラーが発生

```plaintext
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0664 for '.ssh/keypair.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key ".ssh/keypair.pem": bad permissions
```

`chmod 600 ~/.ssh/keypair.pem`コマンドを実行して、パーミッションを変更しました。
http://yachibit.hatenablog.jp/entry/2013/04/25/001912



### `ssh -Y`コマンドで`X11 forwarding request failed on channel 0`が発生
xauthが必要
https://qiita.com/mohi_teak/items/473fda1f03cbd9cc8518


## du
### 今いるディレクトリの容量

```shell-session
$ du -sh ./*/
```

https://www.greptips.com/posts/756/

### ピリオドから始まるディレクトリの容量も算出

```
$ du --block-size=1M --summarize * .[^\.]* | sort --numeric-sort --reverse
```

http://wordpress.honobono-life.info/lin-base/%e3%83%87%e3%82%a3%e3%82%b9%e3%82%af%e4%bd%bf%e7%94%a8%e9%87%8f%e3%81%8c%e5%a2%97%e3%81%88%e3%81%9f%e6%99%82%e3%81%ab%e3%81%a9%e3%81%ae%e3%83%87%e3%82%a3%e3%83%ac%e3%82%af%e3%83%88%e3%83%aa%e3%81%8c/#comment-91298 参照

## mount

### ディレクトリに別ディレクトリをマウント

```shell-session
# mount --bind old_directory new_directory
```

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/storage_administration_guide/sect-using_the_mount_command-mounting-bind

## pkill
たくさん開かれている画像ビューア`ristretto`を、まとめて落とす。

```shell-session
$ # ristretto を終了させる
$ pkill -f ristretto
$ pkill -f gpicview
$ # thunar を終了させる. usernameを指定
$ pkill -f Thunar -u yuji38kwmt
```

https://qiita.com/uraura/items/12ff6112fd392f1be424

# Bash

## 変数関係

* `$_` : 直前のコマンドの最後の引数（`mkdir sample && cd $_`）
http://www.go-next.co.jp/blog/server_network/os/18616/

* `-` : 標準入出力（`cat -`）
 https://www.softel.co.jp/blogs/tech/archives/2151/comment-page-1

### 変数内に改行を含む場合
改行した状態で出力する場合、変数を二重引用符で括ります。

https://ex1.m-yabe.com/archives/3339

```bash:foo.sh
FOO="a
b"

echo ${FOO}
echo "${FOO}"
```

```plain:console
$ ./foo.sh
a b
a
b
```


## その他
### ターミナル上でキー入力を受け付けなくなった場合
https://linux.just4fun.biz/?%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2/%E7%AB%AF%E6%9C%AB%E3%81%8C%E3%82%AD%E3%83%BC%E5%85%A5%E5%8A%9B%E3%82%92%E5%8F%97%E3%81%91%E4%BB%98%E3%81%91%E3%81%AA%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E5%A0%B4%E5%90%88%E3%81%AE%E5%AF%BE%E5%87%A6#e67a90b6

### 実行スクリプトの存在するディレクトリに移動する

```
SCRIPT_DIR=$(cd $(dirname $0); pwd)
pushd ${SCRIPT_DIR}

popd
```

https://qiita.com/koara-local/items/2d67c0964188bba39e29 参照


### よく使うbashオプション

```
#!/bin/bash -euvx
```

https://qiita.com/dskshmz/items/c01f29f8398cc7f5c396 参考

### 「引数リストが長すぎる」というエラー
https://bacchi.me/linux/rm-tips/

```shell-session
$ # カレントディレクトリには、10万件以上の"jpg"ファイルが存在する
$ mogrify -path ../test2 -resize 128x *.jpg 
bash: /usr/bin/mogrify: 引数リストが長すぎます
$ # echoとxargsで解決
$ echo ./*.jpg | xargs  mogrify -path ../test2 -resize 128x  
```

### 10進数に変換

```shell-session
$ echo $(( 008 + 1 ))
bash: 008: 基底の値が大きすぎます (エラーのあるトークンは "008")
$ echo $(( 10#008 + 1 ))
9
```

https://qiita.com/kawaz/items/b29eef5e1934b1995949


### コマンドライン引数の解析

```bash
#!/bin/bash -e

PROGNAME=$(basename $0)

usage_exit() {
        echo -ne "Usage: ${PROGNAME} --project_id PROJECT_ID [--account_id ACCOUNT_ID] [--delete] [--help] \n"  1>&2
        exit 1
}

FLAG_DELETE=false
PROJECT_ID=""
ACCOUNT_ID=""

if [ $# -gt 0 ]; then
    for OPT in "$@"
    do
    case ${OPT} in
        "-p" | "--project_id")
            if [ -z "$2" ]; then
                echo "${PROGNAME}: ${1} オプションには値を設定してください" 1>&2
                exit 1
            fi
            PROJECT_ID=$2
            shift 2
        ;;
        "-a" | "--account_id")
            if [ -z "$2" ]; then
                echo "${PROGNAME}: ${1} オプションには値を設定してください" 1>&2
                exit 1
            fi
            ACCOUNT_ID=$2
            shift 2
        ;;
        "--delete")
            FLAG_DELETE=true
            shift 1
        ;;
        "-h" | "--help")
            usage_exit
        ;;
        -*)
            # 無効なオプションを判定
            echo "${PROGNAME}: illegal option $1" 1>&2
            exit 1
        ;;
        *)
            # 無効なパラメータを判定
            if [ -n "$1" ] && [[ ! "$1" =~ ^-+ ]]; then
                echo "${PROGNAME}: illegal parameter $1" 1>&2
                exit 1
            fi
        ;;  
    esac
    done
fi

if [ -z "${PROJECT_ID}" ]; then
  echo "--project_id は必須" 1>&2
  usage_exit
fi

echo '処理開始'
echo "PROJECT_ID = ${PROJECT_ID}"
echo "ACCOUNT_ID = ${ACCOUNT_ID}"
echo "FLAG_DELETE = ${FLAG_DELETE}"
```

https://qiita.com/b4b4r07/items/dcd6be0bb9c9185475bb 参照

# `.bashrc`関係

### コマンド履歴の前方探索を<kbd>Ctrl+S</kbd>で行う

```bash:.bashrc
stty stop undef
stty start undef
```

https://qiita.com/sasaplus1/items/be55798643ea02179e65
https://linuxfan.info/disable-ctrl-s

### 履歴の上限を増やす
http://oplern.hatenablog.com/entry/2017/03/13/225411

### 複数端末間でコマンド履歴(history)を共有
http://iandeth.dyndns.org/mt/ian/archives/000651.html

### プロンプトの表示を変更
プロンプトが長すぎる場合などは、設定する
https://qiita.com/katsukii/items/da37d1fdf974bd0e4c2f

### 適切なaliasを設定

```.bashrc
alias rm='rm -i'
```

### Gitブランチ名を表示
[git-prompt.sh](https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh)をダウンロードして、以下の設定を行う。

```
source ~/.git-prompt.sh
# ホスト名とユーザ名を緑色、作業ディレクトリを青色、ブランチ名を紫色 で表示
PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\[\033[01;35m\]$(__git_ps1 " (%s)")\[\033[00m\]\$ '
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/06184e06-b052-bcc4-b509-eca737711248.png)