Shell
概要
シェルスクリプトはUnixシェルで使われるProgramming Language。
Memo
ファイルが配置されているディレクトリをカレントディレクトリとする
ディレクトリが関係するシェルスクリプトの場合、実行場所によって結果が変わってしまうことがある。最初にファイルが配置されているディレクトリに移動すればどこでも実行できるようになる。
cd `dirname $0`
高速転送
SSH経由のディレクトリ転送を効率的に行う #Linux - Qiitaのメモ。
SSHで大きなディレクトリを転送したいときが稀にある。普通に考えるとscp(と再帰オプション)で送るものだが、tar+sshで送ると圧倒的に早い。ファイル1つ1つ送るscpは時間がかかる。
tar cf - <ローカル> | ssh <ホスト> 'tar xf - -C <転送先>'
scp -C -r data {HOST}:/dest
xオプションでデバッグする
xオプションを使うと、実行トレースを表示する。デバッグに使える。
bash -x example.sh
プログラムの実行状態を表示する
キャリッジリターンのよくある利用法の1つは、プログラムの実行状態を表示するために用いるというもの。毎回行頭に戻り、直前に表示した文字列を上書きしているので、パーセントだけが変わっているように見える。
#! /bin/sh for i in `seq 100` do printf 'Loading object files...%3d%%\r' $i sleep 0.05 done echo 'Loading object files ... Done'
独習アセンブラに載っていた。
水平タブは表を揃えるのに便利
ls -l . | awk '{ printf "%s\t%s\t%s\n", $9,$5,$3 }' | head
20210508233810-org_roam.org 15343 orange 20210508234743-emacs.org 63296 orange 20210509095513-ruby.org 59766 orange 20210509095946-rails.org 57004 orange 20210509100112-javascript.org 26017 orange 20210509101246-programming_language.org 29086 orange 20210509122633-emacs_lisp.org 55114 orange 20210511013549-textlint.org 11189 orange 20210512001700-create_link.org 9776 orange
タブを使わないバージョン。
ls -l . | awk '{ printf "%s, %s, %s\n", $9,$5,$3 }' | head
, , 20210508233810-org_roam.org, 15343, orange 20210508234743-emacs.org, 63296, orange 20210509095513-ruby.org, 59766, orange 20210509095946-rails.org, 57004, orange 20210509100112-javascript.org, 26017, orange 20210509101246-programming_language.org, 29086, orange 20210509122633-emacs_lisp.org, 55114, orange 20210511013549-textlint.org, 11189, orange 20210512001700-create_link.org, 9776, orange
sudoでセットされる環境変数は異なる
普通の実行時とsudo時で、セットされている環境変数は異なる。
export TEST=1 env # これはTESTを含む sudo env # TESTがない
シェルのバックグラウンド実行
https://github.com/kd-collective/NetBSD/blob/89341ae2e1875e7f91cefa9b1dcc0e4549edcde0/bin/sh/jobs.c#L1716-L1865
STATIC void cmdtxt(union node *n) { union node *np; struct nodelist *lp; const char *p; int i;
if (n = NULL || cmdnleft <
0)
return;
switch (n->type) {
case NSEMI:
cmdtxt(n->nbinary.ch1);
cmdputs(“; ”);
cmdtxt(n->nbinary.ch2);
break;
case NAND:
cmdtxt(n->nbinary.ch1);
cmdputs(“ && ”);
cmdtxt(n->nbinary.ch2);
break;
case NOR:
cmdtxt(n->nbinary.ch1);
cmdputs(“ || ”);
cmdtxt(n->nbinary.ch2);
break;
case NDNOT:
cmdputs(“! ”);
* FALLTHROUGH *
case NNOT:
cmdputs(“! ”);
cmdtxt(n->nnot.com);
break;
case NPIPE:
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
cmdtxt(lp->n);
if (lp->next)
cmdputs(“ | ”);
}
if (n->npipe.backgnd)
cmdputs(“ &”);
break;
case NSUBSHELL:
cmdputs(“(”);
cmdtxt(n->nredir.n);
cmdputs(“)”);
break;
case NREDIR:
case NBACKGND:
cmdtxt(n->nredir.n);
break;
case NIF:
cmdputs(“if ”);
cmdtxt(n->nif.test);
cmdputs(“; then ”);
cmdtxt(n->nif.ifpart);
if (n->nif.elsepart) {
cmdputs(“; else ”);
cmdtxt(n->nif.elsepart);
}
cmdputs(“; fi”);
break;
case NWHILE:
cmdputs(“while ”);
goto until;
case NUNTIL:
cmdputs(“until ”);
until:
cmdtxt(n->nbinary.ch1);
cmdputs(“; do ”);
cmdtxt(n->nbinary.ch2);
cmdputs(“; done”);
break;
case NFOR:
cmdputs(“for ”);
cmdputs(n->nfor.var);
cmdputs(“ in ”);
cmdlist(n->nfor.args, 1);
cmdputs(“; do ”);
cmdtxt(n->nfor.body);
cmdputs(“; done”);
break;
case NCASE:
cmdputs(“case ”);
cmdputs(n->ncase.expr->narg.text);
cmdputs(“ in ”);
for (np = n->ncase.cases; np; np = np->nclist.next) {
cmdtxt(np->nclist.pattern);
cmdputs(“) ”);
cmdtxt(np->nclist.body);
switch (n->type) { * switch (not if) for later *
case NCLISTCONT:
cmdputs(“;& ”);
break;
default:
cmdputs(“;; ”);
break;
}
}
cmdputs(“esac”);
break;
case NDEFUN:
cmdputs(n->narg.text);
cmdputs(“() { … }”);
break;
case NCMD:
cmdlist(n->ncmd.args, 1);
cmdlist(n->ncmd.redirect, 0);
if (n->ncmd.backgnd)
cmdputs(“ &”);
break;
case NARG:
cmdputs(n->narg.text);
break;
case NTO:
p = “>”; i = 1; goto redir;
case NCLOBBER:
p = “>|”; i = 1; goto redir;
case NAPPEND:
p = “>>”; i = 1; goto redir;
case NTOFD:
p = “>&”; i = 1; goto redir;
case NFROM:
p = “<”; i = 0; goto redir;
case NFROMFD:
p = “<&”; i = 0; goto redir;
case NFROMTO:
p = “<>”; i = 0; goto redir;
redir:
if (n->nfile.fd != i)
cmdputi(n->nfile.fd);
cmdputs(p);
if (n->type = NTOFD || n->type =
NFROMFD) {
if (n->ndup.dupfd < 0)
cmdputs(“-”);
else
cmdputi(n->ndup.dupfd);
} else {
cmdtxt(n->nfile.fname);
}
break;
case NHERE:
case NXHERE:
cmdputs(“<<…”);
break;
default:
cmdputs(“???”);
break;
}
}
カレントディレクトリのファイルサイズ
du -sh .
388M .
ファイルサイズのランキング
サイズ順に、もっとも大きい10ディレクトリを表示する。
du -sk * | sort -rn | head -10
360676 node_modules 3696 public 196 package-lock.json 124 20210624232811-digger.org 100 20210910122240-bookmarks.org 72 20210926143813-clojure.org 68 20210907223510-haskell.org 64 20210508234743-emacs.org 56 20210911113057-go.org 56 20210901101339-rust.org
比較するディレクトリサイズによって単位オプションをKBやMBにする。ソートが機能しなくなるので-hオプションは使用しない。
エラー: 公開鍵を利用できないため、以下の署名は検証できませんでした を解決する
sudo apt-get updateしたとき、GPGエラーが出る解決法。
GPG エラー: https://…. focal InRelease: 公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY …
表示されているpubkeyをコピペして、追加する。
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys aaaaaa... # aaaaaa...に、公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY ...← を入れる
cinnamonを再起動する
ウィンドウマネージャを再起動したいときがある。
cinnamon --replace
sourceコマンド
sourceは環境変数関係を再読み込みするのによく使う。
source ~~/.bashrc
みたいに。
bashでは、 .
でもできる。
つまり、 . ~~/.bashrc
と書いても同じ意味になる。
コマンドの実行と出力結果を記録する
script
コマンドが便利。
実行してオンになると、 exit
するまでの履歴をファイルに保存できる。
踏み台を経由したssh
普通にやると、2回sshコマンドを実行するので面倒。 configに記入しておいて、一度に実行する。
Host <alias_name> HostName <target_server> User <target_user> IdentityFile <target_id_rsa> ProxyCommand ssh -W %h:%p -i <bastion_id_rsa> -p <bastion_port> <bastion_user>@<bastion_server>
input関係の設定を.bash_profile等でしてはいけない理由
上記の設定を .bashrc でしないでください。.bashrc はインタラクティブな bash セッションを初期化するときに使われます。インタラクティブでないセッションや X セッションの初期化では用いられません。さらに、.bashrc で環境変数を設定すると、コマンドラインから実行した診断ツールに誤解を与えて、X セッションでは環境変数が使われていないのに正しく設定されているかのように表示されることがあります。
cronで通知する
cronで時報を通知したいけど、表示されないことがある。これはcronがCLI向けのコマンドであって、画面出力があることを想定してないから。
指定する。普通はこれでOK。
export DISPLAY=:0 && notify-send "時報" "$(date +\%H):00!"
cat /var/log/syslog
EXWM + dunstの環境でうまくいかなかった。 DBUS_SESSION_BUS_ADDRESSの設定が必要なよう。参考サイトをコピペすると通知できるようになった。
00 * * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus setpriv --euid=1000 notify-send "Timebot" "$(date +\%H):00!"
Cannot run notify-send from cron job / Newbie Corner / Arch Linux Forums
xargsで一括削除
find . -name "*.log" | xargs rm -fv
findでファイルのリストを作成して、xargsに渡す。 xargsはファイルを1つずつrmに渡す。
xargsにはdry-runモードがある。
find . -name "*.log" | xargs -p rm -fv
xargsでリポジトリ内一括置換
git grep、xargs、sedを組み合わせる。
git grep -l '2\.6\.5' | xargs sed -i 's/2\.6\.5/2.7.1/g'
- git grepの
l
オプションはヒットしたファイル名を出力する。 - xargsは標準出力からリストを読み込み、出力を次のコマンドの引数に渡すコマンド。
- sedは置換。
i
オプションは結果を画面出力しないオプション。 本来はsed -i "s/aaa/bbb/s" Gemfile
みたいな順だが、xargsで自動で渡されている。
一括git clone
GitHubから、 個人 or 組織のリポジトリをすべてダウンロードする方法。
curl https://api.github.com/users/{USER}/repos?per_page=100 | jq .[].ssh_url | xargs -n 1 git clone
curl https://api.github.com/orgs/{ORG}/repos?per_page=100 | jq .[].ssh_url | xargs -n 1 git clone
?per_page=100
をつけないとデフォルトの30件しか取ってこないので注意。
100を超えるとページを指定する必要がある。
参考に読む用リポジトリは、organizationにまとめておく。 ローカルですぐ閲覧できて便利。
Cinnamonのコントロールパネルを出す
これが起動できればサウンドやディスプレイ設定もできる。
cinnamon-settings
失敗時例外を出す
#!/bin/bash set -e # ...
というように、しておくと、実行時できなかったときにエラーメッセージを出す。 何も指定しないと、どこで失敗したのか把握するのが困難。 ローカル環境だといいのだが、CIだと確認コストがかかるので必ず指定しておくとよい。
デバッグメッセージ出力
#!/bin/bash -x # ...
-xをつけると評価結果を逐一出力する。
GNOMEの音量調整
pactl set-sink-volume @DEFAULT_SINK@ +5% pactl set-sink-volume @DEFAULT_SINK@ -5%
カレントディレクトリ行数カウント
wc -l `find ./ -name '*.el'`
git ls-files *.org | xargs wc -c | sort -n
ディレクトリの全ファイルで実行する
for file in `\find ./src -name '*.py'`; do echo $file python $file | sed -e s/.*[0-9]m// >> ./docs/query.org done
port検索する
port already in used. が出たとき。
プロセスを探す。
sudo lsof -i:5432
ポートを使ってるプロセスを削除する。
sudo lsof -t -i tcp:5432 | sudo xargs kill -9
LinuxでWindowsのブートメディアを作成する
woeusbというパッケージをインストールして行う。
sudo add-apt-repository ppa:tomtomtom/woeusb sudo apt update && sudo apt install woeusb-frontend-wxgtk
https://www.omgubuntu.co.uk/2017/06/create-bootable-windows-10-usb-ubuntu
aptコマンド
aptはdebian系ディストリビューションで用いられるパッケージマネージャ。
- パッケージ検索
apt search libffi
suspendする
コマンドでサスペンドする方法。
Ubuntuのとき。
systemctl suspend -i
GNU Guixのとき。
loginctl suspend
プロセスを止める
簡単に検索、killできる。
pgrep firefox pkill firefox