ときどきの雑記帖 RE* (新南口)
ザ・ラストレッドショルダー
ウド篇からクエント篇までの総集編の間に「ザ・ラストレッドショルダー」を入れ込むとはなかなか憎いな:) >アニメ26|BS無料放送ならBS12(トゥエルビ)
ボトムズのOVAの中ではこれが一番好きかな (前日譚(prequel)はあまり好きではないのだけど(例外はもちろんある))。
「身銭を切れ」
読んだんですけどね。 読み進めるのがいろいろ辛かった。
なにがどう辛かったのかとりあえず一つ書いておくと、原著のタイトルが「Skin in the Game」で これは日本語にすると「身銭を切る」というのはその通りではあるんだけど
- Skin in the game (phrase) - Wikipedia
- Skin in the Game (book) - Wikipedia
- skin in the gameの意味・使い方|英辞郎 on the WEB
- skin in the gameの意味・使い方・読み方 | Weblio英和辞書
- 身銭を切る(みぜにをきる)の意味 - goo国語辞書
- 身銭を切る(みぜにをきる)(笑える日本語辞典) 使い方 語源 意味
日本語の「身銭を切る」というのが金銭的なものに限定される(だよね?)のに対して、 この「Skin in the game」はそうでもない(元々は「身銭を切る」そのものだったという 話もあるみたいだけど)ので、 金銭がまるで絡んでいない状況でも「身銭を切る(切れ/切らない)」を連発されて その違和感が積もり積もってもうどうにもならなくなってしまった。
Amazonのレビューでも「Skin in the game」→「身銭を切る」に言及している人はいたんだけど
Amazon.co.jp:カスタマーレビュー: 身銭を切れ 「リスクを生きる」人だけが知っている人生の本質
今回の「身銭を切る」(skin in the game)の翻訳は、意訳してでも「自腹を切る」の方が適当だと思う。
「意訳」の使い方はさておき、「自腹を切る」にしても変わらないような(笑)
「それは内容と関係ないじゃん」というのはまあそうなんだけど、 内容の方もそれはそれで以下略(気になる向きはAmazonのレビュー見て想像して)。 前回の「反脆弱性」も上巻でギブアップしたし、次の新刊があってもスルーかなあ。
glob(そのn+3)
しかし、Bourne Shellでこう何回もかけているとbsshやzshの話になるのはいつになるのか。 さらにはそれぞれをどれだけ追いかけられるのかって話になりますな(笑)
などという話はこれぐらいにして、今回は本筋に戻りつつも方向性を変えて。
v7unix/v7/usr/src/cmd/sh at master ・ v7unix/v7unix
これまでは実際にglobingをしているところから「上へ」辿ろうとしていたのだけど、 mainから「下へ」辿ってみることにする。ということでまずはmain。
v7unix/main.c at master ・ v7unix/v7unix
main(c, v)
INT c;
STRING v[];
{
REG INT rflag=ttyflg;
/* initialise storage allocation */
stdsigs();
setbrk(BRKINCR);
addblok((POS)0);
/* set names from userenv */
getenv();
/* look for restricted */
/* IF c>0 ANDF any('r', *v) THEN rflag=0 FI */
/* look for options */
dolc=options(c,v);
IF dolc<2 THEN flags |= stdflg FI
IF (flags&stdflg)==0
THEN dolc--;
FI
dolv=v+c-dolc; dolc--;
/* return here for shell file execution */
setjmp(subshell);
/* number of positional parameters */
assnum(&dolladr,dolc);
cmdadr=dolv[0];
/* set pidname */
assnum(&pidadr, getpid());
/* set up temp file names */
settmp();
/* default ifs */
dfault(&ifsnod, sptbnl);
IF (beenhere++)==FALSE
THEN /* ? profile */
IF *cmdadr=='-'
ANDF (input=pathopen(nullstr, profile))>=0
THEN exfile(rflag); flags &= ~ttyflg;
FI
IF rflag==0 THEN flags |= rshflg FI
/* open input file if specified */
IF comdiv
THEN estabf(comdiv); input = -1;
ELSE input=((flags&stdflg) ? 0 : chkopen(cmdadr));
comdiv--;
FI
ELSE *execargs=dolv; /* for `ps' cmd */
FI
exfile(0);
done();
}
今どきのbashやzshに比べると短いものではあるのだけどそれでも起動後にいろいろやっていて、 ユーザーからの入力待ちになるのは最後の一つ手前のここ。
exfile(0);
ここから大雑把に関数呼び出しの流れを今回の説明に必要と思われるところだけ追いかけていくとこんな感じになる
exfile
+ execute
| + cmd
| + list
| + term
| + word
| + item
+ getarg
| + split
| + expand
|
+ execa
+ execs
exfileはmainと同じファイル(main.c)にあるこんな関数 (本体部分は省略)。
LOCAL VOID exfile(prof)
BOOL prof;
{
前述のmainからの呼び出しでは0が渡されていた引数 profについてはとりあえず忘れて 先を眺めていくと、コメントに「コマンドループ」と書かれている部分がある。
/* command loop */
LOOP tdystak(0);
stakchk(); /* may reduce sbrk */
exitset();
IF (flags&prompt) ANDF standin->fstak==0 ANDF !eof
THEN IF mailnod.namval
ANDF stat(mailnod.namval,&statb)>=0 ANDF statb.st_size
ANDF (statb.st_mtime != mailtime)
ANDF mailtime
THEN prs(mailmsg)
FI
mailtime=statb.st_mtime;
prs(ps1nod.namval); alarm(TIMEOUT); flags |= waiting;
FI
trapnote=0; peekc=readc();
IF eof
THEN return;
FI
alarm(0); flags &= ~waiting;
execute(cmd(NL,MTFLG),0);
eof |= (flags&oneflg);
POOL
}
ここでも色々やっているけどそこは見ないふりをする。 コマンドラインで入力されたものを実行しているのは 名前からしてそんな感じのここ(ループのラス前)。
execute(cmd(NL,MTFLG),0);
executeの引数として呼び出されているcmd(とその詳細)はとりあえず脇へ置いて、 executeの中身を追いかける。
v7unix/xec.c at ed636a47207476db76d53b7869447889dee3bbad ・ v7unix/v7unix
/* ======== command execution ========*/
execute(argt, execflg, pf1, pf2)
TREPTR argt;
INT *pf1, *pf2;
{
/* `stakbot' is preserved by this routine */
REG TREPTR t;
STKPTR sav=savstak();
sigchk();
IF (t=argt) ANDF execbrk==0
THEN REG INT treeflgs;
INT oldexit, type;
REG STRING *com;
treeflgs = t->tretyp; type = treeflgs&COMMSK;
oldexit=exitval; exitval=0;
SWITCH type IN
とここまできて treeflags
の内容で分岐をするのだけど
このtreeflags
はexecute
に渡された引数である argt
に由来するもの
(ここで先の execute(cmd(NL,MTFLG),0);
を思い出すこと)。
そして続く部分のラベルのところだけ抜き出すとこう
case TCOM:
case TFORK:
case TPAR:
case TFIL:
case TLST:
case TAND:
case TORF:
case TFOR:
case TWH:
case TUN:
case TIF:
case TSW:
ENDSW
exitset();
}
簡単に説明すると内部コマンドだったりifやらcaseやらで分岐しているわけだけど
(先頭のT
はおそらくToken
を表すもの)、
今回は「普通の外部コマンド」を実行する流れを追いかけているのでそれぞれを
細かく見ていくことはしない。
今回注目すべきはここ (のはず。最初、switch caseでfall through しているのを読みそこなって 勘違いしてしまったのはここだけのオハナシ)。
「横幅節約」のため、インデントをいくつか戻しているのでそこんとこよろしく。
se TCOM:
BEGIN
STRING a1;
INT argn, internal;
ARGPTR schain=gchain;
IOPTR io=t->treio;
gchain=0;
argn = getarg(t);
com=scan(argn);
a1=com[1]; gchain=schain;
IF (internal=syslook(com[0],commands)) ORF argn==0
THEN setlist(t->comset, 0);
FI
IF argn ANDF (flags&noexec)==0
THEN /* print command if execpr */
IF flags&execpr
THEN argn=0; prs(execpmsg);
WHILE com[argn]!=ENDARGS
DO prs(com[argn++]); blank() OD
newline();
FI
SWITCH internal IN
(省略)
ENDSW
IF internal
THEN IF io THEN error(illegal) FI
chktrap();
break;
FI
ELIF t->treio==0
THEN break;
FI
END
case TFORK:
IF execflg ANDF (treeflgs&(FAMP|FPOU))==0
THEN parent=0;
ELSE WHILE (parent=fork()) == -1
DO sigchk(); alarm(10); pause() OD
FI
IF parent
THEN /* This is the parent branch of fork; */
/* it may or may not wait for the child. */
IF treeflgs&FPRS ANDF flags&ttyflg
THEN prn(parent); newline();
FI
IF treeflgs&FPCL THEN closepipe(pf1) FI
IF (treeflgs&(FAMP|FPOU))==0
THEN await(parent);
ELIF (treeflgs&FAMP)==0
THEN post(parent);
ELSE assnum(&pcsadr, parent);
FI
chktrap();
break;
ELSE /* this is the forked branch (child) of execute */
flags |= forked; iotemp=0;
postclr();
settmp();
/* Turn off INTR and QUIT if `FINT' */
/* Reset ramaining signals to parent */
/* except for those `lost' by trap */
oldsigs();
IF treeflgs&FINT
THEN signal(INTR,1); signal(QUIT,1);
FI
/* pipe in or out */
IF treeflgs&FPIN
THEN rename(pf1[INPIPE],0);
close(pf1[OTPIPE]);
FI
IF treeflgs&FPOU
THEN rename(pf2[OTPIPE],1);
close(pf2[INPIPE]);
FI
/* default std input for & */
IF treeflgs&FINT ANDF ioset==0
THEN rename(chkopen(devnull),0);
FI
/* io redirection */
initio(t->treio);
IF type!=TCOM
THEN execute(t->forktre,1);
ELIF com[0]!=ENDARGS
THEN setlist(t->comset,N_EXPORT);
execa(com);
FI
done();
FI
この最後の方にある exexa(com)
をみると
v7unix/service.c at master ・ v7unix/v7unix
VOID execa(at)
STRING at[];
{
REG STRING path;
REG STRING *t = at;
IF (flags&noexec)==0
THEN xecmsg=notfound; path=getpath(*t);
namscan(exname);
xecenv=setenv();
WHILE path=execs(path,t) DONE
failed(*t,xecmsg);
FI
}
さらに execsというのを呼び出していて
LOCAL STRING execs(ap,t)
STRING ap;
REG STRING t[];
{
REG STRING p, prefix;
prefix=catpath(ap,t[0]);
trim(p=curstak());
sigchk();
execve(p, &t[0] ,xecenv);
SWITCH errno IN
(省略)
ENDSW
}
と、ここまできてようやく execve(3) に到達。
Ubuntu Manpage: execve - プログラムを実行する
続く。
Galil rule
BM法関連でググってたら過去の自分の書いたものが引っかかった(笑)
Galil rule ってなんだったっけ。とぐぐる
Tanaka さん
小ネタです。末尾に改行が無いファイルに対しsedする時、GNUのsedとBSD(mac)sedで挙動が違います。
最近(つーてもここ一年位?)これに関係するようなGNU sedの仕様変更だか修正の話をみた覚えがあるなあと NEWSやらChangeLogを確かめたがそれっぽい記述は見つからず。
ついでに
Here are a few commonly reported bugs that are not bugs.
などとある sed, a stream editor も見てみたがこの件はないなあ。
というのが前振りで、上記の検索をしている途中でとある方を発見した。 OSSコラム | NTTデータ先端技術株式会社 の「GNUコラム」のところに 田中紀洋というお名前が。 漢字表記なのですぐにはピンとこなかったのだけど…
2017/1/4に正規表現によるマッチング速度が大きく向上したGNU sed 4.3がリリースされました。
従来のリリースには、正規表現によるマッチング・エンジンとしてregexのみ搭載されていました。 regexはPOSIXで規定される全ての正規表現をサポートすることを目標に設計されています。 その結果、コードが複雑であり性能面ではあまり優れていません。そこで、 私はGNU sedと同様に正規表現によるマッチングを行うGNU grepのマッチング・エンジンの1つを GNU sedでも使えるようにしようと考えパッチを投稿しました。その成果が「正規表現によるマッチング速度が大きく向上」です。
GNU grepは、regex以外に2つのマッチング・エンジンを搭載しています。そのうちの1つであるdfaは、 特殊な正規表現をサポートしませんが、性能面ではregexと比較してとても優れています。 dfaは古くからGNU grepに搭載されていますが、ここ数年の間に私とPaul Eggert氏が中心となり、 機能面、性能面および品質面で多くの改善を施してきたマッチング・エンジンです。 私は次のステップとして改善されたdfaの横展開を検討しました。正規表現によるマッチングを多用するプログラムには GNU grep以外にGNU awkとGNU sedがありますが、GNU awkはすでにdfaを使用していたため、 私はGNU sedへdfaのソースコードをコピーし、regexと協調して動作するようにしました。
このコラムでは、GNUの開発に関わるようになったきっかけや苦労話などをご紹介したいと思います。 このコラムをお読みくださった皆さまがOSSの開発や貢献に少しでも興味を抱いていただければ幸いです。
grep.git - grep で頻繁に名前をお見かけしたTanakaさんではないですか。
コラム本文はこちらGNU sed 4.3登場 - 開発に携わって | NTTデータ先端技術株式会社
GNU sed 4.3登場 - 開発に携わって(2017.01.23)
4年前の記事かー。気がつかなかった。
記事が一件だけというのも寂しい気がするけど 何か書く(書き続ける)のも簡単ではないか。
Dignity
「沈黙の艦隊」を思い出した>「尊厳」
同様の連想をする人はほかにもいるらしい(笑)
単純なことほど難しい。Simple is difficult.|takuyama|note
「沈黙の艦隊」、読み返したい気もするんだけどまとめて買うのはちょっとねえ… (いくらまでなら出せるだろうか?)