Skip to content

Latest commit

 

History

History
472 lines (316 loc) · 15 KB

bash-note.md

File metadata and controls

472 lines (316 loc) · 15 KB

.profileや.bash_profileで毎回混乱するので、 きちんと理解する。

参考リンク

.profile, .bash_profileの関係

引用は JM Projectのmanページ 、起動(Invocation)のセクションから。

bash が 対話的(interactive shell)なログインシェル(login shell) として起動されるか、 --login オプション付きの非対話的シェルとして起動されると...

  • 対話的である/対話的でない
  • ログインシェルである/ログインシェルでない

の4通りが有りうるわけで。

ログインシェル(login shell)とは、0 番目の引き数の最初の文字が - であるシェル、または --login オプション付きで起動されたシェルのことです。

echo $0で確認できる。

$ echo $0
-bash
$ bash
$ echo $0
bash
$ ps f
  PID TTY      STAT   TIME COMMAND
 2346 pts/0    Ss     0:00 -bash
 2742 pts/0    S      0:00  \_ bash
 2752 pts/0    R+     0:00      \_ ps f
  • tmuxやscreenだとまた-bashに戻る。
  • sudo -i-bash
  • sudo subash

/etc/profile ファイルが存在すれば、 bash はまずここからコマンドを読み込んで実行します。

このファイルを読んだ後、 bash は

  1. ~/.bash_profile
  2. ~/.bash_login
  3. ~/.profile

をこの順番で探します。 bash は、この中で最初に見つかり、 かつ読み込みが可能であるファイルから コマンドを読み込んで実行します。 (見つけたら、他は読まない)

ログインシェルでない対話的シェルとして起動されると、 ~/.bashrc ファイルがあれば、 bash はここからコマンドを読み込み、実行します。

よくあるスケルトンでは.profile中で.bashrcを読むようなコードが書いてある。

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

引用元: Ubntu 16.04LTSの/etc/skel/.profile

ログインシェルが終了するときには、 ~/.bash_logout ファイルがあれば、 bash はこれを読み込んで実行します

.bash_logoutにssh-agentを殺すような処理を書く例

# if this is the last copy of my shell exiting the host and there are any agents running, kill them.
if [ $(w | grep $USER | wc -l) -eq 1 ]; then
   pkill ssh-agent
fi

引用元: Managing multiple SSH agents - Wikitech

非対話的に実行されると (「例えばシェルスクリプトを実行するために」)、.bashrcも.profile等も読まない。

ただし、環境変数 BASH_ENV という抜け穴がある。

非対話的に実行されると...bash は環境変数 BASH_ENV を調べ、この変数が定義されていればその値を展開し、 得られた値をファイル名とみなして、 そこからコマンドの読み込みと実行を行います。

ただし、ファイル名を探すために PATH 環境変数の値が使われることはありません。

例外がもう1つ

bash は、リモートシェルデーモン rshd やセキュアシェルデーモン sshd によって実行された場合など、標準入力がネットワーク接続に接続された状態で実行されたかどうかを調べます。 この方法によって実行されていると bash が判断した場合、 ~/.bashrc が存在し、かつ読み込み可能であれば、 bash はコマンドをこのファイルから読み込んで実行します。

sh として呼び出された場合には、この動作は行いません。

exit code

/bin/sh, /bin/bashを使って起動したプロセスのexit codeは shが予約している領域があるよ、という話。

exit codes 1 - 2, 126 - 165, and 255

上記の表の通り,Exit Code 1, 2, 126〜165, 255 は特別な意味を持ち,スクリプトやプログラム内で exit に指定するパラメータとしては避けるべきである

あと、POSIXでは64~78が提案されているので /usr/include/sysexits.h これを使うのが行儀がいい(はず)。

たとえばpythonだとosモジュールでos.EX_USAGEなどが定義されている。

ただしWindowsのosモジュールはos.EX_xxxが無い(POSIXじゃないから)。

参考:

特定のフォルダの下にあるスクリプトをすべて実行する

一番かんたんに思いつきそうなのはこれ(実行フラグがついていないものは考えていない)

for p in /etc/cron.daily/* ; do   echo "$p";   sh "$p"; done

少し考えたのはこれ(並列実行20は適当な値)

find /etc/cron.daily -type f -perm /+x | xargs -n1 -P20 sh

もっと良い方法があると思う。↑は複雑すぎる。

ファイルから引数を読み込んで処理

yum install $(<list)

みたいな記述ができる。

上記は

cat list | xargs yum install

と同じ

psの出力を長くする

shellと関係ないけどよく忘れるのでメモ

COLUMNS=999 ps axf

とかでもできるけど

ps axfww

w2個で制限がなくなる。

参考: Man page of PS

tarでリスト

これもshellと関係ないけどよく忘れるのでメモ。 (TODO: なんでよく忘れるか、を考える)

tar ztf foo.tar.gz

または

tar ztvf foo.tar.gz

zcvf,zxvfのc,xのところにt(--list)を使う。

tarで特定のファイルだけ標準出力

-Oオプションとファイルの指定

たまたまあったtarballでの例

tar zxvf yum-r8.tar.gz yum/check_update_security/r8.json -O | jq . | less

ファイル/ディレクトリのmodeを8進数で得る

stat -c "%a %n" *

ディレクトリを指定のモードで作成する

mkdirの-mオプションを使う。

例)

mkdir -m 1770 ~/tmp

mountでディスクを列挙するのをやめる

最近は仮想ファイルシステムが多いので、mountでディスクを列挙しようとすると目が死ぬ。

lsblk --fs が代わりに使える。 ( lsblk -f に同じ )

sudo -e

sudo -e /etc/foobar.conf
# sudo $EDITOR /etc/foobar.conf に同じ

みたいなことができる。かっこいいかもしれない。

hex dump

od -tx1

または

xxd

/rootのfsck

systemdでない場合

まず

fsck -n /

でほんとに異常があるのか確認。

本当にファイルシステムに異常があるなら

shutdown -F -r now

で、再起動時にfsckを実行させる。これはtouch /forcefsckと同じ。

まだ問題があるようなら、CD bootなどで。

参考:

/forcefsckは自動的に削除される。

systemdの場合

ext2,3,4ならtune2fsの-cオプションが使える。

例:

sudo tune2fs -c1 /dev/sda1

でreboot。

xfsなら

sudo xfs_repair -d /dev/sda1

でいいらしい(未確認)。manには「直ちにrebootする」と書いてある。fsck.xfsはダミーのコマンドで、実行しても何も起きない。 RHEL 8のこの記事が参考になる

参考:

同じパスワードでも/etc/shadowで同じ値にならない話

頭にsaltが入ってるから。

実験:

$ mkpasswd -m sha-512
パスワード: # "test"とかタイプする。
$6$cgLIIKwI7G3gP5$BB8lv2ywAMpd6aEh7fv7IPgNrFMGzeWh3kHItFgBrSsjW1jBnhMg1jLRxnf20bR4vCGv/P4OZGhFDj7yAUx/e.
$ mkpasswd -m sha-512
パスワード: # 同じく"test"とかタイプする。
$6$w/4/NSMdk$Uhnu9e6ebwfffnD63QwaRtkztr8/fa4y/Bw5maFWsOH9F/qZ9iL6wB3oiNbJieS3RkuE77QIy7l.1o0ty.fJJ0

# saltを指定してみる
$ mkpasswd -m sha-512 -S 00000000
パスワード:
$6$00000000$Ecw0YyyJ4sK4v4s7/V/HvstYmY48Hthq0T3M/Dr70frxMfGTUbP4llrgm2vTwJbQxGGbP2cDUlvl2QeO6tPwo0
$ mkpasswd -m sha-512 -S 00000000
パスワード:
$6$00000000$Ecw0YyyJ4sK4v4s7/V/HvstYmY48Hthq0T3M/Dr70frxMfGTUbP4llrgm2vTwJbQxGGbP2cDUlvl2QeO6tPwo0
# おなじsaltで同じパスワードならハッシュはおなじになる

mkpasswdはwhoisパッケージに入ってる。

参考: ひつまぶし食べたい: /etc/shadowについて勉強してみた

stderrをless

よくあるこれなんだけど

標準出力とエラー出力を混ぜてless

foobar 2>&1 | less

標準出力を捨てて、エラー出力だけをless

foobar 2>&1 > /dev/null | less

覚えられない。なんか小さいコマンド作って

foobar | err2stdout | less

みたいにできるといいんだけど。

xargsで入力が空の時エラーにしないオプションは

-r, --no-run-if-empty

日付でソート

syslogの出力で、先頭が Jan 19 23:56:40: ... みたいなやつをソートする方法

例)

fgrep -h SomeWordToSearch /var/log/messages* | sort -k1M -k2n -k3

Sort logs by date field in bash

降順にするのは sort -k1Mr -k2nr -k3r とするか、tacコマンドを使う。

bashのショートカットキー

cut & yank あるって知ってました? undoもあるよ。

@-とは

curlで使える構文で、@fileでファイルから読み込む。で、@-でstdinから読み込む。

これとhereドキュメントと組み合わせると

みたいなことができる。

usermod -aG

-aG は 補助グループを追加することができるusermodのオプション。 -G だと上書き。

以下例

# useradd test1
# id test1
uid=1001(test1) gid=1001(test1) groups=1001(test1)

# groupadd g1
# groupadd g2
# usermod -G g1 test1
# id test1
uid=1001(test1) gid=1001(test1) groups=1001(test1),1002(g1)
# usermod -G g2 test1
# id test1
uid=1001(test1) gid=1001(test1) groups=1001(test1),1003(g2)
## 追加したg1が消えてしまう

# usermod -aG g1 test1
# id test1
uid=1001(test1) gid=1001(test1) groups=1001(test1),1002(g1),1003(g2)

lsofの複数条件

オプションをただ並べるとor条件になってしまう。 -aを使うとAND条件になるのだけど

Caution: the -a option causes all list selection options to be ANDed;

「注意:-aオプションは、すべてのリスト選択オプションがANDになります。 選択オプションの間に配置することで、選択されたペアのANDを発生させることはできません。」

# 例: nginxで使っているunixソケットの一覧。
# `-a`はどこにあっても結果は同じ
lsof -a -c nginx -U

参考: Ubuntu Manpage: lsof - list open files