mastodon.zunda.ninja is one of the many independent Mastodon servers you can use to participate in the fediverse.
Zundon is a single user instance as home of @zundan as well as a test bed for changes of the code.

Administered by:

Server stats:

1
active users

僕の使っているコマンドラインツールの 12月1日分はdateコマンドです。

TZ環境変数(候補は/usr/share/zoneinfo以下)を設定して世界時計にしたり(夏時間に注意!!)、

$ TZ=Australia/Sydney date; TZ=Japan date;TZ=America/Los_Angeles date; TZ=Pacific/Honolulu date
Sat Dec 2 09:20:16 AM AEDT 2023
Sat Dec 2 07:20:16 AM JST 2023
Fri Dec 1 02:20:16 PM PST 2023
Fri Dec 1 12:20:16 PM HST 2023

タイムゾーンの変換をしたり(macOSで/bin/dateにあるBSD dateには-dオプションが無いのでbrew install coreutilsなどでGNU dateをインストールする必要があります)、

$ TZ=UTC date -d '2024-01-01 00:00 JST'
Sun Dec 31 03:00:00 PM UTC 2023

ファイル名にタイムスタンプを含めたりできます。

$ echo Hello, World! > hello-`date +%Y%m%d`.txt
$ ls hello-*.txt
hello-20231201.txt

僕は24時間表記の方が便利なのでLC_TIMEをCに設定しています。

$ LC_TIME= date; LC_TIME=C date
Fri Dec 1 12:21:18 PM HST 2023
Fri Dec 1 12:21:18 HST 2023

べんり!!

僕の使っているコマンドラインツールの 12月2日分はシェルです。厳密にはコマンドラインツールじゃないのかもだけど (みんなもこのハッシュタグ使ってもいいんだよ!)

コマンドラインツールを使うには仮想端末(xfce4-terminalとかiTerm2とか)を起動してそこでシェル(bashとかzsh)を起動して、文字でやりとりします。

デフォルトではemacs風のキーコンビネーションでコマンドラインを編集できます。下記は僕の手が覚えているコンビネーションです。例えばCtrlキーを押したままAキーを押す場合、C-aと書きます。ESCキーを押してからDキーを押す場合はM-dと書きます(遠いのであまり使わない)。ここにないコンビネーションは、bashの場合はman bashで、zshの場合はman zshzleで確認できます。bashはreadlineというライブラリを利用していて.inputrcファイルで設定できます。

- C-a 行頭に移動
- C-e 行末に移動
- C-b 左に移動
- C-f 右に移動

- C-r 以前のコマンドラインから検索
- C-p 前のコマンドラインに移動
- C-n 次のコマンドラインに移動

- C-h・バックスペース 前の文字を削除
- C-d 現在位置の文字を削除
- C-k 行末まで削除
- C-w 前の単語を削除
- M-d 後の単語を削除

標準出力の制御をしたくなることもあるかもしれません。sttyで設定できます。

- C-s 出力を一時停止
- C-q 出力の一時停止を解除

シェルから起動したプロセスの制御もできます。

- C-z 現在のプロセスを一時停止する
- fg 一時停止したプロセスを再開する
- bg 一時停止したプロセスをバックグラウンドで再開する

たくさん書きましたがこういうのは指だけが覚えててなかなか頭では思い出せないよねえ。

僕の使っているコマンドラインツールの 12月3日分はvimです。UNIXに触り始めた頃にはemacsでRMAILを使っていましたが、SunOS付属のvi (C-\で素直に落ちる)を触るうちに手が馴染みました。

XubuntuやUbutu Serverではvim-noxを使っています。macOSではOS付属ものを使っています。ほぼデフォルトのままsyntax onでシンタックスハイライトもしてくれてありががたい。

$ sudo apt install vim-nox
$ sudo update-alternatives --set editor /usr/bin/vim.nox

手元の~/.vimrcは下記のような感じになっています。

set sw=2 ts=2 et ai
syntax on
autocmd FileType make set noet ts=8
autocmd FileType rust set sw=4 ts=4

Xubuntuでは下記のようなスクリプトを

#!/bin/sh
set -e

path=$(mktemp -p /tmp scratch.$(date +%Y%m%d-%H%M%S).XXXX.txt)
xsel -o -p > $path
/usr/bin/vim -c 'set enc=utf8 fenc=utf8' $path
cat $path | xsel -i -b
cat $path | xsel -i -p
sleep 0.5

Ctrl-Alt-eから端末を起動してクリップボードの内容をvimで編集しています。

exo-open --launch TerminalEmulator …/bin/scratch.sh

macOSでは下記のようなスクリプトを端末内から起動してクリップボードの内容をvimで編集しています。

#!/bin/sh

ts=`date +%Y%m%d-%H%M%S`
path=`mktemp /tmp/${ts}.XXXX` || exit 1
pbpaste > $path
/usr/bin/vim -c 'set enc=utf8 fenc=utf8' $path
cat $path | pbcopy
echo $path

今日も昨日に引き続き指で記憶モノをお届けしました。

僕の使っているコマンドラインツールの 12月4日分はsshです。奥が深いやつだけれど、このところ身ぢかでは、目の前にXubuntuデスクトップがあって、家の中とか実家にUbuntuサーバがあってsshしてお世話するという構成になっています。昔は-Xとか-YのオプションをつけてX11のウインドウを送ってもらったりしてたんだけどね。認証エージェントの転送とかもしてません。

sshサーバでは/etc/ssh/sshd_configを編集してパスワード認証を禁止します(禁止する前にssh公開鍵を登録しておかないとリモートからログインできなくなります)

PasswordAuthentication no

最近のUbuntuだと/etc/ssh/sshd_config.d/50-cloud-init.confで

yes

とする必要もあるようです。設定を反映するためsudo systemctl reload sshします。

僕はssh元のそれぞれのホームディレクトリでそれぞれの鍵対を管理していて、私有鍵のコピーは作らないようにしています。2カ所以上のssh元からssh先の~/.ssh/authorized_keysに公開鍵を登録しておくことで、私有鍵が失われた場合でも他のssh元からsshできます。

外出しているときにもsshできるようにインターネットからsshできるようにしてあるサーバもあります。sshサーバには固定のプライベートIPアドレスをわりあてて、ルータでポートを転送するようにしています。ssh元のグローバルIPアドレスの範囲は、/etc/hosts.denyに

ALL: ALL

を追加してデフォルトを接続禁止にし、/etc/hosts.allowに許可するログイン元のIPアドレスを追記します。ファイルを書いた次のssh接続から有効になります。

sshd: 192.0.2.0/24

そのうちIPv6対応のためにいろいろと勉強しなくちゃな…。今はルータで全部拒否するようになっています。

僕の使っているコマンドラインツールの 12月5日分はrsyncです。コピー元のディレクトリとコピー先のディレクトリを指定すると更新のある分だけコピーしてくれる便利なコマンドで、僕はおもに家サーバでの日ごとのバックアップに利用しています。リモートへのコピーにも利用できます。

rsyncでのコピー元やコピー先の指定は、最後の / の有無で動作が変わります。注意。

下記は家サーバ(まだcronが動いてる)の/etc/cron.daily/backup-localスクリプトの一部です(このままでは走らないかも)。システム側のディレクトリに含まれるファイルのうち失くしたくないものを/home/backup以下にコピーして、/home全体を/backup以下にコピーしています。

extraopt=
dst=/home/backup
for dir in /etc /usr/local /var/spool/cron; do
dstdir=$dst/$dir
mkdir -p $dstdir
chmod og-rwx $dstdir
rsync -a --delete $extraopt $dir/ $dstdir
done
rsync -a --delete $extraopt /home/ /backup

この後、/backup1に外付けのハードディスクがマウントしてあればそこにコピーして、

if mount | grep -q /backup1 ; then
mkdir -p /backup1/Backup/home
rsync -a --delete $extraopt /home/ /backup1/Backup/home

さらに/bacup2に外付けのハードディスクがマウントしてあれば読み書き可能にリマウントしてBackupとArchive以下をコピーします

if mount | grep -q /backup2 ; then
mount -o remount,rw /backup2 && rsync -a $extraopt /backup1/ /backup2
mount -o remount,ro /backup2
fi

extraopt='-v --dry-run'などとすると試験走行できます。

僕の使っているコマンドラインツールの 12月6日分はscreenです。端末が止まっても止まらない端末のやつ。ナウなヤングはscreenではなくByobuやtmuxを利用するらしいです。

何日かコマンドを走らせ続けておきたい時や、端末での作業内容を同僚(いたんだ)やリモートの自分などと共有したい時に使います。

$ screen

デフォルトではC-aがscreenを操作するためのホットキーとなりますが、僕は行頭に移動するC-aを多用するので、~/.screenrcでC-]に設定しています。続く2行では最初の画面とビジュアルベルを無効にしています。

escape ^]^]
startup_message off
vbell off

screenをデタッチする時は、C-]のあとdをタイプします。screen -list でデタッチされたまま稼動を続けているscreenのリストが表示されるので、

$ screen -x 12345.pts-0.localhost

などとしてアタッチしなおすことができます。デタッチされたscreenがひとつだけの場合はアタッチするscreenを指定する必要はありません。

screen内でシェルを終了させるとscreenも終了します。

僕の使っているコマンドラインツールの 12月7日分はgpgです。OpenPGP準拠の、というかOpenPGPの基になったpgp互換の、非対称鍵暗号を含むハイブリッド暗号を扱うフリーソフトウェアです。

非対称鍵暗号については、手前味噌ですが、 https://mitome.in あたりをざっくり読んでみるとなんとなく理解できた気になるかもしれません。僕とメールなどでのやりとりを暗号化する場合には、https://keyoxide.org/f60960d80b224382ca8d831cb56c20316d6e8279 などから僕の公開鍵を入手してください。暗号化してメールをやりとりするような相手はいまのところ居ないけどな!

僕は、メールの他、ざっくりローカルで情報を保護したい場合にも利用しています。私有鍵と暗号化したファイルを同じ場所に置いてあるので、なにかの拍子に不正ログインされた場合は、私有鍵にかけてあるパスフレーズの強度で情報の保護の強度が決まります。

鍵対のある環境で、暗号化したいファイルsecret.txtから

$ gpg -ea --default-recipient-self secret.txt

して暗号化したファイルsecret.txt.ascを作成して、

$ cat secret.txt.asc | gpg -d

して復号します。私有鍵が必要になるとpinentryがパスフレーズの入力を促し、得られた私有鍵をgpg-agentがしばらくのあいだ覚えておいてくれます。ssh先では端末内でpinentryを起動してもらいたいので、~/.bashrcなどに下記を追加しておきます。

export GPG_TTY=$(tty)

復号できることを確かめたら暗号化前のファイルは消しておきます。

$ shred secret.txt
$ rm secret.txt

https://www.cipherdyne.org/blog/2008/02/interfacing-vim-with-gnupg-encrypted-files.html などを参考に、暗号化したファイルをvimで編集することもできます。

mitome.inmitome.in - 暗号と電子署名を気軽に認め印を使うくらい気軽に、暗号でやりとりしたり電子署名したい

僕の使っているコマンドラインツールの 12月8日分はcurlとjqです。ブラウザなどでウェブサイトがうまく表示されない場合などに、より詳しくサーバとのやりとりを確認することができます。

例えばGitHub pagesにお願いしているページとはIPv6でTLS v1.3で接続しLet's Encryptの証明書を信頼しTLS_AES_256_GCM_SHA384で暗号化してHTTP/2でやりとりすることがわかります。

$ curl -v https://zunda.ninja/
* Trying 2606:50c0:8001::153:443...
* Connected to zunda.ninja (2606:50c0:8001::153) port 443 (#0)
:
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=zunda.ninja
:
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
:

JSONを返すURLはjqでみやすくなります。

$ curl -s https://zunda.ninja/.well-known/webfinger | jq .aliases
[
"https://mastodon.zunda.ninja/@zundan",
"https://mastodon.zunda.ninja/users/zundan"
]

やりとりのどの段階でどれだけ時間がかかったか表示することもできます: https://blog.josephscott.org/2011/10/14/timing-details-with-curl/

ブラウザの開発者ツールからネットワークタブを表示し、確認したいリクエストを右クリックしてcURLとしてコピーし、それを端末にペーストすることで、認証トークンのクッキーなどのヘッダも含めてcurlからリクエストを再現することもできます。認証情報がクリップボードに含まれるので取り扱いに注意しましょう。

zunda.ninjazunda | zunda.ninja
More from zunda

僕の使っているコマンドラインツールの 12月9日分はopensslです。SSLサーバ証明書を確認します。

s_clientでサーバから証明書を取得します。最近はSNIをデフォルトで送ってくれるようですが、下記では-servernameで明示しています。接続後のやりとりは不要なので、「:|」で何もしないコマンドからパイプをつなぎ標準入力を閉じます。(ちょっとかわいい)

$ :| openssl s_client -connect zunda.ninja:443 -servername zunda.ninja -showcerts
CONNECTED(00000005)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = zunda.ninja
verify return:1
:

「-----BEGIN CERTIFICATE-----」から「-----END CERTIFICATE-----」までのブロックがそれぞれの証明書で、上記ではサーバ証明書、中間証明書、ルート証明書の3枚が送られてきました。

x509にパイプして最初の証明書の詳細を確認します。

$ :| openssl s_client -connect zunda.ninja:443 -showcerts 2>/dev/null | openssl x509 -noout -text
:
Issuer: C = US, O = Let's Encrypt, CN = R3
Validity
Not Before: Oct 17 03:42:05 2023 GMT
Not After : Jan 15 03:42:04 2024 GMT
Subject: CN = zunda.ninja
:

2枚目以降の確認には工夫が必要です: https://gist.github.com/zunda/8efe9b184aceb8e930fd56f769084c97

GistRun `openssl x509` on each of certificates obtained with `openssl s_client`Run `openssl x509` on each of certificates obtained with `openssl s_client` - each-cert.sh

僕の使っているコマンドラインツールの 12月10日分はrubyです。僕はBASIC、C、Perl、PHPなどを書いていましたが、2002年ごろにRubyと出会ってからはずっとRubyがいちばん手に馴染んでいます。RubyはGitHubやMastodonなどのソフトウェアを書くこともできます(そういえばTwitterもRubyだったよね!!)が、日常のちょっとした作業にもとても便利です。

カニクリームコロッケする:

$ ruby -e 'puts "カニクリームコロッケ".chars.shuffle.join'
ロカムクコニケッリー

UTF-16で𠮷野家の文字数を数える:

$ ruby -e 'puts "𠮷野家".encode("UTF-16").chars.size'
4

うちのルータのIPアドレスがプライベートなものか確認する:

$ ruby -ripaddr -e 'puts IPAddr.new("192.168.1.1").private?'
true

素因数分解する:

$ ruby -rprime -e 'p 42.prime_division'
[[2, 1], [3, 1], [7, 1]]

最近では、Advent of Code https://adventofcode.com/ をRubyで解いています。基礎的なアルゴリズムが標準添付で揃ってるのがとってもラク!! 非正方行列の逆行列とかも手軽に得られたら機械学習ブームにも乗っかってたのかな。

adventofcode.comAdvent of Code 2023

僕の使っているコマンドラインツールの 12月11日分はsortとuniqです。テキストファイルとして保存された行ごとのデータなどを扱う時には、Rubyなどでプログラムを書くよりも小さいコマンドを組み合わせた方が簡単なこともあります。UNIX哲学だよ!
https://ja.wikipedia.org/wiki/UNIX%E5%93%B2%E5%AD%A6

例えば、bashのコマンド履歴から多く実行しているコマンドを知るには、cutコマンドで行頭のコマンド名を抽出し、辞書順に並べ、同じ行を数え、数字の逆順に並べ、最初だけを取り出します:

$ cut -f1 -d' ' .bash_history | sort | uniq -c | sort -nr | head
66 cat
35 git
31 cd
30 screen
27 ssh
24 vi
22 tail
20 ls
15 vim
14 man

てかviとvimと両方使ってるんだw

ja.wikipedia.orgUNIX哲学 - Wikipedia

僕の使っているコマンドラインツールの 12月12日分はgnuplotです。データを集計したらグラフにして眺めてみたくなる!!

例えば、syslogの行数を眺めてみます。手元ではsyslogは下記のような形式です。

Dec 12 09:30:27 misoan systemd[1]: Mounted /boot/efi.
Dec 12 09:30:27 misoan systemd[1]: Reached target Local File Systems.

ざっくり分以降を取り除いて1時間ごとの行数を集計します。

$ cut -d: -f1 syslog | uniq -c > logs.dat

各行には、その時刻の行数と月・日・時が記録されます。

2746 Dec 12 09

ここからgnuplotの出番。X軸を時刻としてフォーマットを指定し、X軸のラベルのフォーマットを指定し、各軸のタイトルを指定し、棒グラフの横幅を30分間分に指定しておいて、2カラム目以降をX軸、1カラム目をY軸として棒グラフをプロットします。

$ gnuplot
gnuplot> set xdata time
gnuplot> set timefmt "%b %d %H"
gnuplot> set format x "%b %d\n%H:%M"
gnuplot> set xlabel "Time (HST)"
gnuplot> set ylabel "syslog lines/hour"
gnuplot> set boxwidth 1800
gnuplot> set style fill solid
gnuplot> plot "logs.dat" using 2:1 with boxes

画像ファイルとして保存するには例えば下記のように操作します。

gnuplot> set term push; set term png small; set output "logs.png"
gnuplot> replot
gnuplot> unset output; set term pop

朝の起動時にログが多く記録されること、11日の夜はAdvent of Codeのために2度目の起動をしたことがわかります。10日の夕方電源を切る前にログが多いのはどうしてだろう…。

zunda

僕の使っているコマンドラインツールの 12月13日分はawkです。Rubyで書くほど複雑ではないけれど各行処理では済まないデータの集約に便利です。

ここでは https://gist.github.com/zunda/f566e2bb85ca0616d351139363274ec5 で取得したActivityPubサーバの情報を集計してみます。先週取得した情報がタブ区切りで20231205.tsv
に保存されています。

まず、。-F\\tで入力をタブ区切りにします。

$ awk -F\\t '/^#/{for(i=1;i<=NF;i++){print i,$i}}' 20231205.tsv
1
2 software
3 version
4 users_total
5 users_active_month
6 local_posts
7 peers
8 checked_at
9 error
10 nodeinfo_versions

mastodoサーバの月あたりアクティブユーザ数の平均と標準偏差を求めてみます。標準偏差は、各データの自乗の平均から平均の自乗を引いた結果の平方根として求められます。データが得られなかった場合には * が記録されていますので除外します。

$ awk -F\\t '{if($2=="mastodon"&&$5!="*"){s+=$5;s2+=$5*$5;n++}}END{avg=s/n;stddev=sqrt(s2/n-av*av);print(avg,stddev)}' 20231205.tsv
137.306 5164.52

標準偏差が平均よりずいぶん大きいです。正規分布から離れていて、平均や標準偏差にはあまり意味がなさそうですね。

ざっくり大きさ分布を求めてみます。ユーザ数の桁数で分けます。

$ awk -F\\t '{if($2=="mastodon"&&$5!="*"){print int(log($5)/log(10))}}' 20231205.tsv | sort | uniq -c
8512 0
1312 1
483 2
109 3
14 4
2 5
1080 -inf

アクティブユーザ数が1桁のサーバがほとんどのようです。

Gistcrawler to measure size distribution of ActivityPub serverscrawler to measure size distribution of ActivityPub servers - crawl-activitypub.rb

僕の使っているコマンドラインツールの 12月14日分はsedとgrepです。どちらもパイプの一部として行ごとの情報の加工に便利です。

例えば、HerokuアプリでもあるこのMastodonサーバのconfig var (プラットフォームに覚えておいてもらう環境変数)のうち、エラーやメンテナンスの時に表示するURLを抽出できます。

$ heroku config | grep _PAGE_URL
ERROR_PAGE_URL: //mastodon-offline.zunda.ninja/500.html
MAINTENANCE_PAGE_URL: //mastodon-offline.zunda.ninja/maintenance.html

PostgreSQLやRedisへの接続情報のうちユーザー名やパスワードを隠すこともできます (下記ではホスト名やデータベース名も編集してあります):

$ heroku config | grep 'DATABASE_URL\|REDIS_TLS_URL' | sed 's/:\/\/.*@/:\/\/(redacted)@/'
CACHE_REDIS_TLS_URL: rediss://(redacted)@redis.example.com:12659
DATABASE_URL: postgres://(redacted)@postgres.example.com:5432/mastodon
REDIS_TLS_URL: rediss://(redacted)@redis.example.com:30349
SIDEKIQ_REDIS_TLS_URL: rediss://(redacted)@redis.example.com:21839

そういえばsedは実は奥が深くてラベルへの条件分岐もできたりして、たぶんチューリング完全だったよね

僕の使っているコマンドラインツールの 12月15日分はmanとinfoです。マニュアルです。

いにしえから使われているツールにはmanページと呼ばれるマニュアルが付いている可能性が高いです。manというコマンドで閲覧できます。早速閲覧してみます。簡単な紹介、起動方法、詳細などが読めます。例や関連項目も役に立ちます。

$ man man
:
NAME
man - an interface to the system reference manuals

SYNOPSIS
man [man options] [[section] page ...] ...
:

DESCRIPTION
:
1 Executable programs or shell commands
2 System calls (functions provided by the kernel)
3 Library calls (functions within program libraries)
4 Special files (usually found in /dev)
5 File formats and conventions, e.g. /etc/passwd
6 Games
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
8 System administration commands (usually only for root)
9 Kernel routines [Non standard]

manページは上記のように節に分かれています。例えばprintfコマンドについては

$ man 1 printf

printfライブラリ関数については

$ man 3 printf

で閲覧できます。

GNU製のツールには、より詳細なinfoページが付いている可能性もあります。

$ info autotools

新しくツールを使い始める時には、ざっと使ってみて疑問に思ったことを頭におきつつmanやinfoを一読すると分かりやすかもしれません。使い慣れてきた頃に一読するとより多くの使い方を見つけられるかもしれません。

僕の使っているコマンドラインツールの 12月16日分はdigとwhoisです。DNSします。

僕は+noall +answerを付けるのがお気に入り。弊ぼっちのCNAMEレコードは1時間で、Aレコードは10秒で無効になるようです。

$ dig +noall +answer mastodon.zunda.ninja
mastodon.zunda.ninja. 3600 IN CNAME mastodon.zunda.ninja.herokudns.com.
mastodon.zunda.ninja.herokudns.com. 9 IN A 54.91.59.199
mastodon.zunda.ninja.herokudns.com. 9 IN A 52.20.78.240
mastodon.zunda.ninja.herokudns.com. 9 IN A 3.232.242.170
mastodon.zunda.ninja.herokudns.com. 9 IN A 3.220.57.224

うまく名前解決できないときは+traceすることもあります。

$ dig +trace mastodon.zunda.ninja

DNSサーバを指定することもできます。

$ dig +noall +answer @8.8.8.8 mastodon.zunda.ninja

IPアドレスから持ち主を知りたくなる場合もあります。得られた情報の公開は制限されている場合もあるので注意が必要です。

$ whois 54.91.59.199

ドメインの持ち主のことがわかることもあります。

$ whois zunda.ninja

AWSのIPアドレスの場合は https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html から詳細な情報を得られる場合があります。 https://gist.github.com/zunda/06445a6d14e9fc53bc08354a5c8311e0 のようなスクリプトで、弊ぼっちのロードバランサはus-esat-1にあることがわかります(EC2とIPアドレス範囲を共有しているようです)。

$ ruby aws-ip-range.rb 54.91.59.199
54.91.59.199: us-east-1 on EC2

これはどうして動いてるのかわからないスクリプト https://gist.github.com/zunda/0dcc1001ec404eb7ca00b260a55d4c52

docs.aws.amazon.comAWS IP address ranges - Amazon Virtual Private CloudLists the IP address ranges for AWS.

僕の使っているコマンドラインツールの 12月17日分はqrencodeです。QRコードをつくります。

僕はパスワードを家のsshサーバで管理していて、電話からログインする場合にはどうにかして端末から電話にコピーしないといけません。コマンドの実行履歴にはパスワードを残したくないので、ラップトップで下記のコマンドにコピーペーストしてEnterを押しCtrl-dを押して電話で読みます。サービスによっては末尾の改行を無視してくれないので、trコマンドで削除しています。

$ tr -d '\n' | qrencode -t utf8

自分のサイトを案内するQRコードを自分で作成することもできます。世の中にはQRコードを作ってくれるサービスもありますが、サービスが管理しているURLからリダイレクトするものだとサービスが停止してしまった場合に利用できなくなったり、サービスの管理者が変わった場合にリダイレクト先が変化してしまったりする場合があるので、注意が必要です。下記では-iオプションでアルファベットの大文字と小文字の区別を無くしてQRコードを小さくしています。

$ echo -n https://zunda.ninja | qrencode -i -o qr.png

vCardという規格に従って作成したテキストをQRコードにすることで名刺代わりにすることもできます。OPENPGP4FPRとして記載されているOpenPGP公開鍵については https://mitome.in を参照してみてください。

$ cat <<_END | qrencode -o vcard.png
BEGIN:VCARD
FN:zunda
URL:https://zunda.ninja
EMAIL:zundan@gmail.com
KEY:OPENPGP4FPR:F60960D80B224382CA8D831CB56C20316D6E8279
END:VCARD
_END

QRコードは便利ですが、誰でもアクセスできる場所に掲載してあるQRコードは改竄されている可能性があるので注意が必要ですよね。

僕の使っているコマンドラインツールの 12月18日分はfindとxargsです。ファイルを見つけます。

findコマンドは第1引数に指定したディレクトリからディレクトリを辿って条件に合うファイルを標示してくれます。

$ find . -name '*.rb'

複数の条件を指定するとデフォルトでは論理積になります。例えばvendorディレクトリを除外する場合には論理和を明示する必要があります。

$ find . -name vendor -prune -or -name '*.rb'

ファイル名をコマンドライン引数にして渡す場合にはxargsにパイプします。

$ find . -name vendor -prune -or -name '*.rb' | xargs grep require_relative

ファイル名に空白文字が含まれる場合には、findやxargsにnil文字(\0)を区切り文字にしてもらいます。

$ find . -name vendor -prune -or -name '*.rb' -print0 | xargs -0 grep require_relative

find単体でもファイルの削除などをすることができますが、僕は念のためxargsにechoを渡して実行されるコマンドを目視確認してからechoを削除して実行することが多いです。

$ find . -name vendor -prune -or -name '*.rb~' -print0 | xargs -0 echo rm

それでも探しものが見つからないこともあるんだよね。それより僕と踊りませんか? (いいえ)

僕の使っているコマンドラインツールの 12月19日分はaptかapt-getです。DebianとかUbuntuのパッケージを管理します。「と」じゃなくて「か」なのはマシンによってその場の雰囲気でなんとなくどちらを使うか決まってしまうからです。一度使うとコマンド履歴からいつもそちらを使うようになる。

日々の作業で必要なパッケージが入っていないことに気づいた時には、

$ sudo apt install rbenv

などとしてパッケージをインストールします。ときどき、

$ sudo apt update

もしておきます。

サーバにログインする時に

4 updates can be applied immediately.
4 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

などとメッセージが表示されば場合には、

$ sudo sh -c 'apt update && apt dist-upgrade -y'

して更新します。sudoを1度で済まして認証がタイムアウトしないようにしています。リブートが必要な場合にはログイン時にも表示されますが、表示されるまで遅延があるようなので、

$ cat /var/run/reboot-required*

して確かめます。

cat: '/var/run/reboot-required*': No such file or directory

と言われた場合にはリブートは必要ありません。

日々のパッケージの更新は、 https://help.ubuntu.com/community/AutomaticSecurityUpdates に従って、unattended-upgrades パッケージにお任せしています。リブートの必要なパッケージの更新があった場合には、ログイン時のメッセージに従ってリブートします。

前職のUbuntuサーバでたぶん自動更新がきっかけで必要なサーバが止まっちゃったことがあったのだけれど、今はそんなに特殊なことしてないし…。

help.ubuntu.comAutomaticSecurityUpdates - Community Help Wiki

僕の使っているコマンドラインツールの 12月20日分はgitです。コードやテキストの変更を管理します。

この余白はgitそのものの利用手順を書くには狭すぎるので置いておくとして、ワーキングコピーでシェルのプロンプトにワーキングコピーの状態を知らせてもらえると、未コミットの変更や未pushのコミットがあると*や>が見えて不安にさせてもらえるのがすごく便利です。

Xubuntuではbashを使っていて、~/.bashrcに下記のような行を追加してあります。

case "$TERM" in
xterm*|rxvt*)
if type __git_ps1 >/dev/null 2>&1; then
GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWUPSTREAM="auto"
PS1="${PS1/\\$ /}\$(__git_ps1)\$ "
fi
PS1=${PS1/\$ /\\n$ }
;;
*)
;;
esac

macOSではzshを使っていて、~/.zshrcに下記のような行を追加してあります。.git-sh-promptファイルはUbuntuの/usr/lib/git-core/git-sh-promptをコピーしてきたものです。https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh と同様の内容です。

source ~/.git-sh-prompt
GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWUPSTREAM="auto"
NEWLINE=$'\n'
setopt PROMPT_SUBST
PS1='%F{green}%n@%m%f:%F{cyan}%~%f $(__git_ps1)${NEWLINE}$ '

例えばMastodonのワーキングコピーに居ると下記のようなプロンプトになります。=ならローカルに変更はなくoriginと同期されていてあんしん。

zunda@misoan:~/c/src/github.com/zunda/mastodon (use-ruby33-react-router-5=)
$

GitHubgit/contrib/completion/git-prompt.sh at master · git/gitGit Source Code Mirror - This is a publish-only repository but pull requests can be turned into patches to the mailing list via GitGitGadget (https://gitgitgadget.github.io/). Please follow Documen...

僕の使っているコマンドラインツールの 12月21日分はmailです。postfixとlogwatchも入れてメールを送ってもらいます…コマンドラインツールじゃないな…。

Ubuntuなどではbsd-mailxとpostfixを入れてメールを送るコマンドmailとメールを配送するサービスpostfixを利用します。

Googleでアカウントを作って(常用のものを使うと乗っ取りを疑われてかスパムとして扱われる確率が増えました)、MFAを有効にしてアプリケーションパスワードを作って /etc/postfix/sasl/passwd に記録します。chmod og-rwxするのを忘れない。sudo postmap /etc/postfix/sasl/passwd しておきます。

[smtp.gmail.com]:587 ユーザーID@gmail.com:****

postfixはInternet siteとして設定して、/etc/postfix/main.cf の対応する行を編集して sudo service postfix restart します。

relayhost = [smtp.gmail.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl/passwd
smtp_sasl_security_options = noanonymous
smtp_use_tls = yes
inet_interfaces = localhost

これでメールを送れるようになります。

$ echo "Hi!" | mail -s Test 自分のメールアドレス

rootへのメールをローカルユーザー経由で自分に転送します。/etc/aliases に下記のような行を追記して、sudo newaliasesします。

root: ローカルユーザーID

ローカルユーザーの~/.forwardに自分のメールアドレスを書いておきます。

sudo visudoしてDefaultsをmail_badpassからmail_alwaysにするとsudoするたびにメールをもらえます。logwatchパッケージを入れると毎日syslogなどのまとめを送ってもらえます。文字数

僕の使っているコマンドラインツールの 12月22日分はtopとhtopです。CPUやメモリを使っているプロセスを見せてくれます。

目の前のコンピュータの反応がなんだか遅いなあと思ったときは。topしてみます。システム全体のロードアベレージやメモリの状況と、CPUを利用している順にプロセスの情報を定期的に更新しつつ見せてくれます。ほとんどの場合はブラウザががんばって働いてるけれど、自分の書いたコードがタイトな無限ループに陥っていたりすると見えることがあります。

htopは各CPUコアの利用状況を見せてくれます。プログラムのビルド時には、コンパイルのプロセスが並列化されているのを眺めることができます。Goで書かれたプログラムがたくさんのgo routineを走らせていると、負荷が各コアにきれいに分配されているのを眺めることができます。

目の前のコンピュータの反応が遅いのにあまりCPUが利用されていない場合、fuseを利用しているファイルシステムに不具合があったことがありました。こういうのはどうやって見つけるんだ…。

僕の使っているコマンドラインツールの 12月23日分はstraceです。Linuxでシステムコールを記録してもらいます。コードを読まずに設定ファイルのパスなどを知ることができます。

rbenvで管理しているRubyを起動してみます。-ffで子プロセスごとに記録先のファイルを作ってもらいます。-oで指定した名前にプロセスIDを追加してくれます。

$ strace -e trace=file -ff -o ruby.strace ruby -e 'puts "Hello, World!"'
Hello, World!

けっこうたくさんプロセスを作るんだねえ!

$ ls -1 ruby.strace.*
ruby.strace.193452
:
ruby.strace.193477

今回は記録の多いものを覗いてみます。

$ wc -l ruby.strace.* | sort -nr | head -3
:
1757 ruby.strace.193452
90 ruby.strace.193474
$ cat ruby.strace.193452
execve("/home/zunda/.rbenv/shims/ruby", ["ruby", "-e", "puts \"Hello, World!\""], 0x7fffa148ef88 /* 28 vars */) = 0
:
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
execve("/home/zunda/.rbenv/shims/bash", ["bash", "/home/zunda/.rbenv/shims/ruby", "-e", "puts \"Hello, World!\""], 0x7ffe09972058 /* 28 vars */) = -1 ENOENT (No such file or directory)
:

~/.rbenv/shims/rubyはbashスクリプトなんだねえ!(びっくりしてばかり)

僕の使っているコマンドラインツールの 12月24日分はpsとlsofです。プロセスの様子と開いているファイルなどを見てみます。

ここでは、herokuコマンドを起動してみます。

$ heroku pg:psql -a app-name

psコマンドで関連するプロセスのIDを探します。

$ ps a | grep heroku | grep -v grep
3677 pts/0 S+ 0:00 bash /usr/bin/heroku pg:psql
3684 pts/0 Sl+ 0:01 /usr/lib/heroku/bin/node /usr/lib/heroku/bin/run pg:psql

fオプションで親子関係を、wオプションで端末の幅を越えてコマンドラインを表示してもらいます。nodeがスクリプトを実行し、ローカルでpsqlコマンドを実行しています。

$ ps afw
PID TTY STAT TIME COMMAND
:
3104 pts/0 Ss 0:00 bash
3677 pts/0 S+ 0:00 \_ bash /usr/bin/heroku pg:psql
3684 pts/0 Sl+ 0:01 \_ /usr/lib/heroku/bin/node /usr/lib/heroku/bin/run pg:psql
3695 pts/0 S+ 0:00 \_ /usr/lib/postgresql/14/bin/psql --set PROMPT1=app-name::DATABASE%R%# --set PROMPT2=
:

lsofコマンドでpsqlプロセスを探すとデータベースサーバとのTCP接続が見えます。

$ lsof -i tcp | grep 3695
psql 3695 zunda 3u IPv4 47834 0t0 TCP misoan:36458->postgres.example.com:postgresql (ESTABLISHED)

Private Spaceアプリだともっと複雑でたのしいよ!!

僕の使っているコマンドラインツールの 12月25日分はedです。やっぱりオチはedよね。

ちょくちょく使うわけじゃないんだけど、少なくともUbuntu (Herokuでも!)とmacOSでは何もしないでも使えるようになっています。すごくない?

(Ubuntu 22.04.3 LTS)

$ which ed
/usr/bin/ed
$ apt-cache rdepends ed | sed '1,2d;/ed:/d'
patch
ubuntu-standard
sn
quilt
opensmtpd
mksh
lsb-core
libproc-invokeeditor-perl
libdebbugs-perl
libcupt4-2
debmirror
|changetrack
apt-cacher
ubuntu-standard

(macOS Ventura 13.6.1/M1)

$ which ed
/bin/ed

行ごとにテキストファイルを編集します。ファイル名を指定して起動し、

$ ed hello.txt
hello.txt: No such file or directory

iで入力を始め、

i
Hello, World!

.で入力を終わり、wでファイルに保存してqで終了します。

.
w
14
q
$ cat hello.txt
Hello, World!

既存のファイルを編集してみます。

$ ed hello.txt
14

aで行を追加します。UTF-8も通るんだ!

a
こんにちは、世界
.
w
39
q
$ cat hello.txt
Hello, World!
こんにちは、世界

行の移動もできます。2行目に移動してから行を追加します。

$ ed hello.txt
39
2
こんにちは、世界
a
来年もよろしくね
.
w
64
q
$ cat hello.txt
Hello, World!
こんにちは、世界
来年もよろしくね

というわけで、来年もどうぞよろしくです。