docker exec -it container bash
お馴染み,Dockerコンテナーcontainer
の中に入るコマンドですね。
docker
exec
bash
の意味は知ってる人が多いと思います。-i
も検索すればすぐ分かります。しかし,-t
については情報があまりありません。
そこで,この記事では-t
がどういう意味を持つのか解説していきます。
対象読者
- 何も考えず
docker exec -it container bash
と打っている人 - Linuxの基礎コマンド(
ls
など)を触ったことがある人 - リダイレクト・パイプなど,簡単な入出力操作ができる人
公式ヘルプによる-t
の説明
とりあえず,淡い期待を抱いて公式のヘルプを見てみましょう。
docker exec --help
によると-t
は
-t, --tty
Allocate a pseudo-TTY
ということらしいです。
……何を言っているのかサッパリ分かりませんね。「Allocate a pseudo-TTY」は和訳すると「疑似TTYを割り当てる」ですが,和訳したからといって分かるものでもありません。
この記事では,このヘルプの意味するところの理解を目指して解説を進めます。
実行例の前提環境
以降ではcontainer
という名前のDockerコンテナーを使ってコマンドの実行例を載せていくので,その基となるDockerイメージのソースコードを載せておきます。docker exec
は実行中のコンテナーにしか実行できないのでcontainerの中ではシェルスクリプトが無限ループするようになっています。
FROM ubuntu
COPY wait.sh .
RUN chmod u+x wait.sh
CMD ./wait.sh
#!/bin/bash
while true
do
:
done
-t
以外のところを押さえる
まずは,docker
exec
-i
container
bash
について説明しておきます。本丸の-t
に取り掛かる前に,外堀をきちんと埋めるということです。
「もうそんなことは知ってる」という人は次の章まで読み飛ばしてください。
docker exec
はDockerコンテナーの中でコマンドを実行するコマンドです。冒頭の例docker exec -it container bash
でいうと,「コンテナーcontainer
の中でbash
を実行する」ということになります。
コンテナー内で実行されたコマンドの標準出力・標準エラー出力は,dockerコマンドの標準出力・標準エラー出力として見ることができます。-it
は要りません。
takechan@virtual-machine:~$ sudo docker exec container echo 'Hello, world!!'
Hello, world!!
takechan@virtual-machine:~$ sudo docker exec container cat bin/
cat: bin: Is a directory
takechan@virtual-machine:~$
-i
は--interactive
の略で,dockerコマンドへの標準入力をDockerコンテナー内のコマンドに伝えます。
下の例だと,コンテナー内のgrepコマンドに
- sh
- terminal
- bash
- console
- zsh
- teletype
の6文字列を標準入力で渡し,その中から「sh」を含む
- sh
- bash
- zsh
を抽出してもらっています。-i
を付けないと上手く動作しないのが分かりますね。
takechan@virtual-machine:~$ sudo docker exec container grep -e sh << END
> sh
> terminal
> bash
> console
> zsh
> teletype
> END
takechan@virtual-machine:~$ sudo docker exec -i container grep -e sh << END
> sh
> terminal
> bash
> console
> zsh
> teletype
> END
sh
bash
zsh
takechan@virtual-machine:~$
-t
は無くても良いのではないか
ここまでの説明で-t
以外のところは分かってもらえたかと思います。いよいよ本丸,と言いたいのですが,-t
のことを一旦忘れて
docker exec -i container bash
としたらどうでしょうか。実行するとコンテナー内でbashが起動されて,
- 標準入力は
-i
によってコンテナー外部に接続される - 標準出力・標準エラー出力はオプション無しでもコンテナー外部に接続されている
となります。
標準入力・標準出力・標準エラー出力の3つがコンテナー外と繋がっているため,コンテナー外のbashを操作するようにコンテナー内のbashを操作 できます できそうですができません 。
「百聞は一見に如かず」ということでやってみましょう。比較のために-t
を付けた版(記事冒頭のコマンドと同じ)でも同じ操作をしてみます。
takechan@virtual-machine:~$ sudo docker exec -i container bash
echo 'Hello, world!!'
Hello, world!!
exit 0
takechan@virtual-machine:~$ sudo docker exec -it container bash
root@0345c75af34e:/# echo 'Hello, world!!'
Hello, world!!
root@0345c75af34e:/# exit 0
exit
takechan@virtual-machine:~$
なんと,プロンプトが出てこなくなってしまいました。しかし,ダメ元でecho 'Hello, world!!'
とコマンドを打つと「Hello, world!!」と出力があるのでbashは動いているようです。
exit 0
と打てばログアウトはできますが,「exit」という出力は見られません。
-t
が無い版はプロンプトが出ていないので,どれが入力したコマンドでどれが出力なのか分かりにくくなっています
原理はともかく,Dockerコンテナーに入るとき-t
が無いと困ることは確認できました。それでは,いよいよその原理の解説に入っていきます。
TTYとは12
公式ヘルプによる-t
の説明では,「TTY」という用語が出てきます。
-t, --tty
Allocate a pseudo-TTY
この用語を深掘りしてみましょう。
TTYは「TeleTYpe」(「テレタイプ」と読む)の略で,文字を送信するキーボードと受信した文字を印刷する印刷機が一体になったハードウェアです。コンピューターとの入出力に使われていたらしいです。
キーボードでコンピューターに入力するスタイルは今も使われていますが,コンピューターからTTYに出力があったときは機械がガションガションと動いて紙に文字が印刷されるわけです。Wikipediaの記事では機械感あふれるTTYの画像が見られますが,ディスプレイなどという物が存在しなかった当時はそれぐらいしか出力の手段が無かったんですね。
ディスプレイが登場すると,ディスプレイの上で仮想的にTTYを再現するソフトウェアが開発されました。皆さんお馴染み,
- Windows Terminal
- Tera Term
- ターミナル(macOS標準のアプリケーション)
などです。これらのソフトウェアが実現する仮想的なTTYでは,紙に文字を印刷する代わりにその文字を画面に表示します。また,タブ・ウィンドウ切り替えなどの操作があるので,仮想的なTTYに対応する数だけキーボード・ディスプレイを用意する必要もありません。キーボードからの入力は,タブ・ウィンドウ切り替えで選択されているTTYからの入力として扱われます。
また,Telnet・SSHも仮想的なTTYを実現する手段と言えます。
物理的なTTYはほぼ絶滅しましたが,仮想的なTTYはコンピューターの中で残り続け今日に至ります。今では「TTY」=「仮想的なTTY」と言っても差し支えありません。
TTYはコンピューターで動くプロセスの標準入力にキーボードからの入力を伝えたりプロセスからの標準出力・標準エラー出力を受け取って表示したりするわけですが,標準入力・標準出力・標準エラー出力はTTYとのやり取りに使われるだけではありません。リダイレクトによってファイル3とやり取りさせられたり,パイプによって別のプロセスとやり取りさせられたりすることも多々あります。
仮想化によってソフトウェアなどが多少挟まるようにはなりましたが, CUIプロセスから見て人間に最も近い末端(ターミナル)に位置するのがTTY だということは登場してからずっと変わりません。4
TTYの検出
Linuxコマンドの中には, 標準入力・標準出力・標準エラー出力がTTYに繋がってるかを検知し,それによって挙動を変える ものが存在します。本章ではそのことについて詳しく解説します。
予備知識
ファイルを 結合して 表示するコマンドとして有名なcatですが,標準入力との結合もできます。標準入力を受け付けるのは
- ファイル名の代わりに
-
が指定されたとき - ファイル名が1つも指定されていないとき
の2つです。ファイル名が1つも指定されていないときは標準入力と結合するファイルが他に無いので,標準入力をそのまま標準出力に流します。
この「そのまま流す」特性がこの記事での実験にすごく便利なので覚えておいてください。 相変わらず結合以外の用途にしか使われないcatコマンドが可哀想
TTYの検出を実験してみる
cat
は標準入力をそのまま標準出力に渡すだけなので,パイプで他のコマンドと接続しても全く意味の無いように見えます。
takechan@virtual-machine:~$ echo 'Hello, world!!'
Hello, world!!
takechan@virtual-machine:~$ echo 'Hello, world!!' | cat
Hello, world!!
takechan@virtual-machine:~$ echo 'Hello, world!!' | cat | cat | cat
Hello, world!!
takechan@virtual-machine:~$ grep -e sh << END
> sh
> terminal
> bash
> console
> zsh
> teletype
> END
sh
bash
zsh
takechan@virtual-machine:~$ cat << END | grep -e sh
> sh
> terminal
> bash
> console
> zsh
> teletype
> END
sh
bash
zsh
takechan@virtual-machine:~$ cat << END | cat | cat | grep -e sh
> sh
> terminal
> bash
> console
> zsh
> teletype
> END
sh
bash
zsh
takechan@virtual-machine:~$
しかし,前に述べた「標準入力・標準出力・標準エラー出力がTTYに繋がってるかによって挙動を変える」コマンドはcat
を噛ませるだけで挙動を変えられます。
takechan@virtual-machine:~$ ls
image snap
takechan@virtual-machine:~$ ls | cat
image
snap
takechan@virtual-machine:~$
上のコードブロックでは表現できていませんが,ls
の方の出力には色が付いていてls | cat
の方ではただの白文字が出力されている,という違いもあります。
lsコマンドは「標準入力・標準出力・標準エラー出力がTTYに繋がってるかによって挙動を変える」コマンドの1つです。1つ目の実行例ls
では,lsコマンドの入出力は全てTTYに繋がっています。一方,2つ目の実行例ls | cat
ではlsコマンドの標準出力がcatコマンドの標準入力に渡されます。catコマンドは受け取ったデータを何も加工せずTTYに出力(画面に表示)するのでlsコマンドの標準出力は実質的にTTYと繋がっている,とも言えますが,lsコマンドは機械的に「TTYでないところに標準出力が繋がっている」と判断し,1つ目の実行例とは違う挙動を見せたのです。
「TTYに繋がっているか」が挙動を変える基準となっているのは「データをやり取りする相手が人間か,プログラムか」を判断する良い材料だからです。
前にも述べた通り,TTYはCUIプロセスにとって人間に最も近いところでありすぐ向こう側には人間がいます。人間にデータを見せるときは読みやすさを重視することが多いです。色を付けたり改行位置を調整したりするのが有効です。
一方,パイプの向こう側にはプログラムがいます。プログラムにデータを見せるときは機械的処理のしやすさを求められることが多いです。行数が増えても良いからデータ区切りは全て改行に統一する,着色は制御文字が混ざってしまうのでやらない,などの設計が求められます。
ファイル3は人間が見ることもありますが,どちらかと言えばプログラムによって処理される用途が多いので後者にあたります。
ヒアドキュメントは使い捨てのファイル3をその場で生成して標準入力に繋ぐようなものなので,考え方はファイル3と大差ありません。ちなみに,コマンドから見るとヒアドキュメントはパイプでありTTYとは判定されません。
catコマンドのように何もしないコマンドがTTYとの間に挟まっていると不自然な挙動を見せますが,機械的な判断なので仕方ありません。
このように,コマンドの中には「データをやり取りする相手が人間かプログラムか」を判断して挙動を変えるものが存在します。
TTYの検出には,そのコマンドの思想が現れる
ここまで「TTYに繋がっているかによって挙動を変える」という話をしてきましたが,標準入力・標準出力・標準エラー出力のどれを見てどのように挙動を変えるか,という具体的な仕様はコマンドによってバラバラです。
例えば,lsコマンドは標準出力しか見ておらず標準入力・標準エラー出力がTTYに繋がっているかは気にしません。lsコマンドは標準入力を読まないので,標準入力は判断材料にしていないのでしょう。標準エラー出力にはエラーメッセージが出力されますが,人間向け/プログラム向けで形式に差が無いので気にしていないと考えられます。
上の例ではcat
に影響されない側として登場していたgrepコマンドも「標準入力がTTYかどうか気にしていない」というだけであって,標準出力をTTY以外に繋ぐと文字への着色が無くなります(上の例では着色をコードブロックで表現できていないですが)。「人間が読みにくいような巨大ファイルから必要な行のみ抽出して人間が読む」という用途があるため,標準入力がTTYでなくても標準出力がTTYなら人間向けの動作をすべきという思想があるのでしょう。
一方のbashは,lsコマンドやgrepコマンドと違って標準入力と標準エラー出力を見ます。bashは,そのどちらかがTTYに繋がっていないと判断するとプロンプトや終了時の「exit」5を出力しなくなります。標準出力がTTYかどうかは気にしていません。
takechan@virtual-machine:~$ bash << END
> echo 'Hello, world!!'
> exit 0
> END
Hello, world!!
takechan@virtual-machine:~$
takechan@virtual-machine:~$ bash 2>stderr.txt
echo 'Hello, world!!'
Hello, world!!
exit 0
takechan@virtual-machine:~$ cat stderr.txt
takechan@virtual-machine:~$
takechan@virtual-machine:~$ bash
takechan@virtual-machine:~$ echo 'Hello, world!!'
Hello, world!!
takechan@virtual-machine:~$ exit 0
exit
takechan@virtual-machine:~$
bash 2>stderr.txt
以下ではプロンプトが出ていないので,どれが入力したコマンドでどれが出力なのか分かりにくくなっています。
bash
は標準入力でコマンドを受け付け,標準エラー出力にプロンプトやエラーメッセージ,「exit」を出力します。標準出力はほぼ使いません6。
bash 2>stderr.txt
でプロンプトや「exit」が表示されないのは標準エラー出力がstderr.txtにリダイレクトされているから,と考えてしまいますが,その後cat stderr.txt
を実行しても何も表示されないのでそもそも出力されていないことが分かります。
プロンプトはコマンドの入力要求を人間に分かりやすく伝えるためのものなので
- 人間がプロンプトを読んで(標準エラー出力がTTY)
- 人間がコマンドを入力する(標準入力がTTY)
のどちらかが欠けたらプロンプトを出す意味が無くなる,ということでしょう。加えて,標準エラー出力をプログラムが読む(TTYに繋がっていない)場合にプロンプトはノイズでしかありません。
このように,コマンドは標準入力・標準出力・標準エラー出力がTTYに繋がっているかを検出して各々の思想に基づき挙動を変えます。
-t
は,コンテナー内のコマンドに入出力先が人間だと伝える
前章の
プロンプトや「exit」が表示されない
という現象,見覚えがありますよね。そう,docker exec -i container bash
(-t
抜き)の挙動です。
なんと,プロンプトが出てこなくなってしまいました。しかし,ダメ元で
echo 'Hello, world!!'
とコマンドを打つと「Hello, world!!」と出力があるのでbashは動いているようです。
exit 0
と打てばログアウトはできますが,「exit」という出力は見られません。
つまり, -t
を抜いたとき,コンテナー内bashの標準入力・標準エラー出力はTTYに繋がっていない のではないかという仮説が立てられます。
実際に検証してみましょう。今実行しているbashへの標準入力・標準出力・標準エラー出力がどこに繋がっているか見るにはls -l /proc/${$}/fd/
,標準入力がTTYか判定するにはtty
というコマンドを使います17。
takechan@virtual-machine:~$ sudo docker exec -i container bash
ls -l /proc/${$}/fd/
total 0
lr-x------ 1 root root 64 Jun 2 04:05 0 -> pipe:[18486]
l-wx------ 1 root root 64 Jun 2 04:05 1 -> pipe:[18487]
l-wx------ 1 root root 64 Jun 2 04:05 2 -> pipe:[18488]
tty
not a tty
exit 0
takechan@virtual-machine:~$ sudo docker exec -it container bash
root@0345c75af34e:/# ls -l /proc/${$}/fd/
total 0
lrwx------ 1 root root 64 Jun 2 04:06 0 -> /dev/pts/0
lrwx------ 1 root root 64 Jun 2 04:06 1 -> /dev/pts/0
lrwx------ 1 root root 64 Jun 2 04:06 2 -> /dev/pts/0
lrwx------ 1 root root 64 Jun 2 04:06 255 -> /dev/pts/0
root@0345c75af34e:/# tty
/dev/pts/0
root@0345c75af34e:/# exit 0
exit
takechan@virtual-machine:~$
sudo docker exec -i container bash
以下ではプロンプトが出ていないので,どれが入力したコマンドでどれが出力なのか分かりにくくなっています。
tty
コマンドは標準入力がTTYに繋がっていると判断するとファイル名8,繋がっていないと判断すると「not a tty」を出力します。それを踏まえて上の実験結果を見ると,-t
を付けることでコンテナー内bashの標準入力がTTYになったことが確認できます。また,ls -l /proc/${$}/fd/
の結果より,-t
を付けたときは標準出力・標準エラー出力も標準入力と同じTTYに繋がっていることが読み取れます。一方,-t
を抜いた場合はコンテナー内bashの入出力がパイプに繋がっているようです。
要するに,「-t
を抜いたとき,コンテナー内bashの標準入力や標準エラー出力はTTYに繋がっていない」という仮説は正しかったわけです。そして,上の例で-t
を付けたとき出てきた/dev/pts/0
こそが 疑似TTY(pseudo-TTY) です。疑似TTYは前に述べた「仮想的なTTY」の一種と思ってもらって良いです。
-t
を付けた場合,付けなかった場合のそれぞれでTTY周りがどのように接続されているかを図にしてみました。9
この図を踏まえて公式ヘルプの説明
-t, --tty
Allocate a pseudo-TTY
を見てみると,ヘルプの言いたいことが大体分かるようになっているのではないでしょうか?
-t
を付けるか,付けないか10
ここまでで-t
の意味するところは分かったかと思います。それを踏まえると, コンテナー内のコマンドに人間向けの動作をしてほしいとき-t
を付ける ,という運用が適切だと言えます。
docker exec -i container bash
では,コンテナー外でコンテナー内のbashとやり取りしているのはTTY(人間)なのにコンテナー内のbashは「プログラムとやり取りしている」と判断してプログラム向けの動作をしてしまいました。その結果,bashはプロンプトを出さず人間は不便な思いをしました。これは -t
が必要なのに付けなかった場合 の一例です。
それとは逆に, -t
を付けてはいけないのに付けてしまった場合 も問題になります。以下の例では,コンテナー内でlsコマンド,コンテナー外でwcコマンド(行数を数える)11を用いてディレクトリ・ファイルの数を数えようとしています。
takechan@virtual-machine:~$ sudo docker exec container ls
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
wait.sh
takechan@virtual-machine:~$ sudo docker exec -t container ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var wait.sh
takechan@virtual-machine:~$ sudo docker exec container ls | wc --lines
20
takechan@virtual-machine:~$ sudo docker exec -t container ls | wc --lines
2
takechan@virtual-machine:~$
12
-t
を付けると正しい答えが得られていないことが分かります。コンテナーの外で出力を受け付けるのはwcコマンドなのに,lsコマンドに人間向けの出力をさせてしまったのが元凶ですね。
これは簡単な例なので,wc --words
を用いて単語数を数える11という回避策があります。ただ,人間向けの出力を強引にプログラムで処理するのは良くないです。
上の例で分かったように,「コンテナー内のコマンドに人間向けの動作をしてほしいとき-t
を付ける」のが大原則です。ただ,その原則に従えない場合があります。コンテナー外からコンテナー内コマンドへの標準入力がTTYでない場合です。
実はdocker exec -it
も「標準入力・標準出力・標準エラー出力がTTYに繋がってるかによって挙動を変える」コマンドの1つで,標準入力がTTYでない場合にエラーを出します。「コンテナー外からコンテナー内のコマンドに入力しているのはプログラムなのに,コンテナー内のコマンドが人間向けの動作をしてしまう」という状況を回避するためでしょう。この動作から,「標準入力がTTYでないなら,どのようなコマンドも人間向けの動作をするはずが無い」というフールプルーフ14的思想が見えます。
しかし,標準入力がTTYでなくても標準出力がTTYなら人間向けの動作をする,というコマンド(grepなど)もあるためこの思想での「フール」(「馬鹿」)が本当にフールとは言えません。そういったコマンドをdocker exec -it
で動かすとき,コンテナー外からの標準入力がTTYでないだけで人間向けの動作を禁止されて不便を感じるかもしれません。
この記事の結論としては,こうした docker exec -it
の仕様も時折思い出しながら「コンテナー内のコマンドに人間向けの動作をしてほしいとき付ける」という原則に基づいて-t
を付けたり外したりする のが良いと思います。
まとめ
この記事の内容をまとめると以下のようになります。
- TTYは,人間がCUIを使うためのインターフェース
- 一部のコマンドは,自身の入出力がTTYに繋がっているかに基づいて人間向け/プログラム向けの動作をする
-
docker exec
において-t
は,コンテナー内のコマンドをTTYに繋ぐ=コンテナー内のコマンドに人間向けの動作をさせる -
-t
は付け得ではなく,付けない方が良いとき・付けられないときも存在する
あとがき
僕はDocker初学者で,この記事を書く前もDockerについて学んでいました。その中で引っかかったところを調べているうちに内容が膨らみ,この記事ができました。
同じところで引っかかっている人のモヤモヤを晴らせれば幸いです。
-
参考:宮崎悟. “第32回 端末について知ろう”. CTC教育サービス. 2021-08. https://www.school.ctc-g.co.jp/columns/miyazaki/miyazaki32.html, (参照2024-06-03). ↩ ↩2
-
参考:Wikipedia. “テレタイプ端末”. Wikipedia. 2023-10-30. https://ja.wikipedia.org/wiki/テレタイプ端末, (参照2024-06-03). ↩
-
TTYもパイプも厳密にはファイルですが,ここではそういった特殊なファイルを含めないで「ファイル」と呼んでいます。 ↩ ↩2 ↩3 ↩4
-
あくまで「人間とやり取りするときに」TTYを通るだけで,TTYを一切介さずに完結するものは多々あります。 ↩
-
exitコマンドはbashの組み込みコマンドなので,bashのプロセス上で動作しています。 ↩
-
数少ない例として,組み込みコマンド
echo
は標準出力を使用します。とは言え,動作が単純すぎて人間向けにもプログラム向けにも使えてしまうので判断基準には入っていないのでしょう。 ↩ -
参考:Wikipedia. “tty”. Wikipedia. 2023-11-21. https://ja.wikipedia.org/wiki/Tty, (参照2024-06-03). ↩
-
「デバイスファイル」と呼ばれる特殊なファイルです。仮想的なものも含め,コンピューターに繋がるデバイスと対応しています。 ↩
-
実は,/dev/pts/1もsudoコマンドが用意した仮想的なTTYです。画像では分かりやすさを重視して省略していますが,/dev/pts/1と人間の間にはsudoコマンドとTTY
/dev/tty2
がいます。 ↩ ↩2 -
「
docker exec
でコンテナー内コマンドに疑似TTYを繋ぐ方法が-t
しか無いのはどうなのか」という話もあるのですが,複雑すぎるのでここでは取り上げません。 ↩ -
参考:西村めぐみ. “【 wc 】コマンド――テキストファイルの文字数や行数を数える”. atmarkIT. 2016-11-07. https://atmarkit.itmedia.co.jp/ait/articles/1611/07/news026.html, (参照2024-06-02). ↩ ↩2
-
sudo docker exec -t container ls
では出力が1行に収まっていたのに,sudo docker exec -t container ls | wc --lines
で「2」と表示されるのは一見すると妙に思えます。しかし,wc --lines
の代わりにcat
を入れて実験してみるとlsコマンドの出力行数が本当に変わっていることが分かります。
推測にはなりますが,この現象にはTTYの幅が関係していると考えられます。lsコマンドは人間向けの動作においてTTYの幅を取得13し,それに基づいて人間が見やすいように改行を入れていると考えられます。また,dockerコマンドがコンテナー内に仮想的なTTY(lsコマンドから幅を参照される)を用意するときはdockerコマンドの標準出力先となっているTTYを参照して同じ幅を設定しようとすると考えられます。標準入力のTTYから高さ・幅を取得するコマンドstty size
を用いてコンテナー内TTYの幅を取得する実験をした結果,この動作はdockerコマンドの標準出力先がTTYである場合のみ上手くいっているようです。dockerコマンドの標準出力先がcatコマンドの場合は,コンテナー内TTYの高さ・幅が0になっています。
dockerコマンドがTTYでない標準出力から幅を参照しようとして失敗した,ということでしょう。結果として,コンテナー内TTYの幅を参照したlsコマンドの出力行数が変わったと考えられます。TTYの幅が0になっているという異常事態でも2行で出力しているのは,適当な幅を推測しているからでしょう。
上の実験ではcat
を用いましたが,wc --lines
を用いたときでも同様の現象が起こり「2」が出力される結果になったと考えられます。
この注釈の内容を図にまとめると次のようになります。9 ↩ -
参考:KusaReMKN. “ターミナルの幅と高さに関するメモ書き”. Zenn. 2020-10-10. https://zenn.dev/kusaremkn/articles/abdbd2f38c3d98b145eb, (参照2024-06-02). ↩
-
株式会社FAプロダクツ. “フールプルーフとは?導入事例、メリットと意外な注意点か解説”. おしえてJSS. https://jss1.jp/column/column_433/, (参照2024-06-08). ↩