僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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
べんり!!
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー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 一時停止したプロセスをバックグラウンドで再開する
たくさん書きましたがこういうのは指だけが覚えててなかなか頭では思い出せないよねえ。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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
今日も昨日に引き続き指で記憶モノをお届けしました。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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で
とする必要もあるようです。設定を反映するため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対応のためにいろいろと勉強しなくちゃな…。今はルータで全部拒否するようになっています。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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'などとすると試験走行できます。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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も終了します。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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で編集することもできます。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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からリクエストを再現することもできます。認証情報がクリップボードに含まれるので取り扱いに注意しましょう。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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で解いています。基礎的なアルゴリズムが標準添付で揃ってるのがとってもラク!! 非正方行列の逆行列とかも手軽に得られたら機械学習ブームにも乗っかってたのかな。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー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
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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日の夕方電源を切る前にログが多いのはどうしてだろう…。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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 #domain
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桁のサーバがほとんどのようです。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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は実は奥が深くてラベルへの条件分岐もできたりして、たぶんチューリング完全だったよね
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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を一読すると分かりやすかもしれません。使い慣れてきた頃に一読するとより多くの使い方を見つけられるかもしれません。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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 。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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コードは改竄されている可能性があるので注意が必要ですよね。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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
それでも探しものが見つからないこともあるんだよね。それより僕と踊りませんか? (いいえ)
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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サーバでたぶん自動更新がきっかけで必要なサーバが止まっちゃったことがあったのだけれど、今はそんなに特殊なことしてないし…。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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=)
$
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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などのまとめを送ってもらえます。文字数
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 12月22日分はtopとhtopです。CPUやメモリを使っているプロセスを見せてくれます。
目の前のコンピュータの反応がなんだか遅いなあと思ったときは。topしてみます。システム全体のロードアベレージやメモリの状況と、CPUを利用している順にプロセスの情報を定期的に更新しつつ見せてくれます。ほとんどの場合はブラウザががんばって働いてるけれど、自分の書いたコードがタイトな無限ループに陥っていたりすると見えることがあります。
htopは各CPUコアの利用状況を見せてくれます。プログラムのビルド時には、コンパイルのプロセスが並列化されているのを眺めることができます。Goで書かれたプログラムがたくさんのgo routineを走らせていると、負荷が各コアにきれいに分配されているのを眺めることができます。
目の前のコンピュータの反応が遅いのにあまりCPUが利用されていない場合、fuseを利用しているファイルシステムに不具合があったことがありました。こういうのはどうやって見つけるんだ…。
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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スクリプトなんだねえ!(びっくりしてばかり)
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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アプリだともっと複雑でたのしいよ!!
僕の使っているコマンドラインツールの #ひかえめなアドベントカレンダー2023 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!
こんにちは、世界
来年もよろしくね
というわけで、来年もどうぞよろしくです。