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がない

シェルのバックグラウンド実行

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 と書いても同じ意味になる。

sshが切れたときに処理が止まらないようにする

nohupをつけて実行すると、SSHが切れても実行され続ける。

nohup make long_job &

sshが切れた時に処理が止まらないようにする - Qiita

コマンドの実行と出力結果を記録する

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>

踏み台サーバを飛び越えて一発で目的のサーバへsshする方法 - Qiita

input関係の設定を.bash_profile等でしてはいけない理由

Fcitx - ArchWiki

上記の設定を .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

【Linux】xargs コマンドの使い方がよく分からない - きゃまなかのブログ

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

Tasks

References

stedolan/jq: Command-line JSON processor

jsonを扱う便利コマンド。