Diary

Diary

日々学んだことをアウトプットする場として初めてみました

POSIX 組み込みシェル変数まとめ

POSIX 組み込みシェル変数まとめ

一覧紹介

以下のまとめの中から興味あるものが見つかったら、是非説明の方も見て試していただきたいです。

以下の例は、基本的には頭に「$」を付けて使います。

例えば、一番上の「$」の例でいえば、

$ echo $$
3108612

のようにすると取得できます。

  • $
    • 現在のシェルのプロセス ID
  • #
    • 今のプロセスに渡されたパラメータの数
  • @
  • *
    • すべてのコマンドライン引数。" の中では、ひとつの引数としてまとめて扱われる
  • ?
    • 直前のコマンドの終了ステータス
  • PIPESTATUS
    • パイプで連結した各コマンドの終了ステータス
  • 0 (zero)
    • どのシェルが動いてるか(bash? zsh?)
  • !
    • 最後に走ったバックグラウンドコマンドのプロセス番号
  • ENV
  • HOME
  • IFS
    • 内部的なフィールドのセパレーター。言葉をセパレートする働きをする文字の集まり
  • LANG
  • LC_ALL
  • LC_CTYPE
  • LC_MESSAGES
  • LINENO
    • 行番号が入っている
  • PATH
    • コマンドの検索に使われるパス
  • PPID
    • 親プロセスのプロセスID
  • PS1
  • PS2
    • プロンプトで行を続けるときの文字。デフォルトでは "> ".
  • PS4
    • "set -x" などでトレースした時に区別で使われる文字。デフォルトでは "+ ".
  • PWD

以下ではいくつかのコマンドについて詳しくみていこうと思います。

(すこし)詳細説明

$

プロセスIDを表示する。被りのないユニークな一時ファイルを作りたい時、その名前などに利用されることがある。

$ echo $$
$ touch tmp.$$

?

直前のコマンドの終了ステータスを表し、成功が「0」で失敗がそれ以外を表しています(0が成功に注意)。

失敗の終了ステータスのデフォルト値で有名なものには、以下のようなものがあります。

終了ステータス 説明
1-125 コマンドが失敗して終了した
126 コマンドはあるが実行権がない
127 コマンドが見つからない
128+n シグナル番号 n によって終了した

終了ステータスを発生させる一例

# 0 (成功時)
$ echo hoge
hoge
$ echo $?
0

# 1-125 (失敗時)
$  ls | grep pien
$ echo $?
1
$ ls pien
ls: cannot access 'pien': No such file or directory
$ echo $?
2

# 126
$ sudo chmod -x /bin/ls
$ ls
bash: /usr/bin/ls: Permission denied
$ echo $?
126
$ sudo chmod +x /bin/ls  # 元に戻しておく

# 127
$ pien

Command 'pien' not found, did you mean:
...
$ echo $?
127

# 130 (SIGINT = Ctrl + C がシグナル番号 2)
$ sleep 100
^C      # Ctrl + C で終了する
$ echo $?
130

# 148 (SIGTSTP = Ctrl + Z がシグナル番号 20)
$ sleep 100
^Z
[1]+  Stopped                 sleep 100
$ echo $?
148

# 128 + n
# 2つのターミナルを使う(以下はn=19の例)
(terminal1)$ sleep 100
# 下の出力の中からそれっぽいPIDを探す
(terminal2)$ ps aux | grep sleep
(terminal2)$ kill -19 3271076  # 19のところは好きな数字
(terminal1)$ [2]+  Stopped                 sleep 100
(terminal1)$ echo $?
147

PIPESTATUS

パイプで連結した各コマンドの終了ステータスを表します

# fuga がマッチしなかったため失敗(1)を返す
$ echo hoge | grep fuga
ubuntu@ubuntu:/home$ echo $?
1

# パイプは複数あるため、全部表示するには
# [@]とする必要があることに注意
$ echo hoge | grep fuga
$ echo "${PIPESTATUS[@]}"
0 1

0

ログインシェルかそうじゃないかで出力結果が異なる

# ログインシェルの場合
$ echo $0
/usr/bin/bash
# 新たなbashに変える
$ bash
# 非ログインシェルの結果
$ echo $0
bash
$ exit     # 元に戻っておく

!

最後に走ったバックグラウンドコマンドのプロセス番号が入っている

スクリプトの中で、バックグラウンド処理を非同期的に終了させたい時に便利

$ sleep 100 &
[3] 3272613
$ echo $!
3272613
$ kill $!

ENV

現在の環境変数の値を表示します。((cf) setは、シェル変数が表示します)

$ env
SHELL=/bin/bash
ROS_VERSION=1
COLORTERM=truecolor
TERM_PROGRAM_VERSION=1.58.2
...
$ env | wc
     45      54    3646

PATH

シェルがコマンドを探しに行く場所を表します。いわゆる「パスを通す」というのは、この環境変数に値を登録することをいいます。

$ echo $PATH
bash: /opt/ros/noetic/bin:/home/ubuntu....

# (おまけ)上の表記は見づらいので、縦に並べる
$ echo $PATH | tr ':' '\n'
/opt/ros/noetic/bin
/home/ubuntu/.vscode
...

PPID

親プロセスのプロセスIDを表します。

プロセスにも親子関係があり、詳細はpstreeコマンドで確認できる(今回は割愛)。

# 新しく立ち上げたシェルではプロセスID($$)が異なる
# 新しいシェルの親プロセスIDは、生成元と一致する
$ echo $$ | xargs echo $$ && bash -c 'echo $$ && echo $PPID'
3108612 3108612
3273622
3108612

PS1, PS2, PS4

この辺をいじるとかっこいいオリジナルなターミナルを作れます!

おわりに

今回はぜひ覚えておきたいシェル変数を紹介しました。

詳細を覚えるのではなく、適切なタイミングで使っていけるように頭の片隅に残しておきたいと思っています。