ときどきの雑記帖 RE* (新南口)
はるかなる朝
今週のしずえさん
「ドレッシングの日」
新・電子立国
新・電子立国 (#4092113) | IBM PC、40周年を迎える | スラド
新・電子立国のマイクロソフトの回と、ビジネスソフトの回で取り上げられてましたね。 半導体を扱った電子立国のほうのDVDセットは売ってるのに、新の方は売ってないんだよなあ。 今は許可されないネタが多い?
「新」の方は全体的にもなんか「イマイチ」だった印象しかないのだけど、 (確かその死の数日前だった)ゲイリー・キルドールのインタビューはもう一回観たくはある。 あるいは今観たらシリーズ全体に対する印象や感想も違ったものになるかもしれない。
インタビューにはビル・ゲイツ、ポール・アレン、アラン・ケイ、スティーブ・ウォズニアック、ティム・パターソン、ジム・クラーク、 ゲイリー・キルドールなど、ソフトウエア史を語る上で重要な人物が数多く登場している。 中でもゲイリー・キルドールへのインタビューはキルドールが急死する2日前に撮られたという非常に貴重なものとなっている。 一方でマーク・アンドリーセンへのインタビューのチャンスがありながらそれを逃したことや、 スティーブ・ジョブズへのインタビューを申し入れたが断られたため過去の映像を使わざるを得なかったことなど、 前作に劣らずインタビューには困難が多かったことを、ディレクターの相田洋が後に著書で明らかにしている。
グラスハーフフル
これは、Java 17が「グラス・ハーフ・フル」リリースである可能性がある一方で、 言語の進化における1つの主要なマイルストーンであることを意味する。
This means that while Java 17 may be a “glass half full” release, it does represent another major milestone in the evolution of the language.
グラス・ハーフ・フルとは一体どういう意味なのか と疑問を持ったので調べてみたがよくわからん。
えいご1日1語: あなたは楽観的? ― half-full glass
心理テストなんかで聞く、グラス(コップ)に半分だけ飲み物(水)をみてどう思うか ってアレに関係しているようではあるのだけど。
重箱の隅
生き様106. 「キャリア」の誤解と「キャリア」の本質:コレがワタシの生きる様:エンジニアライフ
まずは、先日の豪雨災害に被災された方に哀悼の意を申し上げます。
xargs
なんとなく「延長戦」
マジックナンバー
教えてもらった 10th UNIXのxargs.cのソースコード を眺めていたらこんな記述を発見
case 's': BUFLIM = atoi(flagval);
if( BUFLIM>470 || BUFLIM<=0 ) {
sprintf(Errstr, "0 < max-cmd-line-size <= 470: %s\n", *argv);
ermsg(Errstr);
}
break;
どこから出てきたんだこの470。 しかもエラーメッセージにも直に文字列として埋め込まれてもいるし。
そういえば古のunixマガジンにコマンドのソースコードを読んでいく連載があって、 unixマガジン別冊としてまとめられていたような (xargsは取り上げられていなかったと思うけど)。
ああ、これだこれ。
strcmp
また、以下の通り、クォート内の置換文字列は-Jオプションでは認識されないようです。
FreeBSDの現状のものであって、macにあるものとは大小問わず違いがある可能性はさておき こんなコードで判定していた。
freebsd-src/xargs.c at main · freebsd/freebsd-src · GitHub
do {
if (Jflag && strcmp(*argv, replstr) == 0) {
char **avj;
jfound = 1;
argv++;
for (avj = argv; *avj; avj++)
cnt += strlen(*avj) + 1;
break;
}
cnt += strlen(*bxp++ = *argv) + 1;
} while (*++argv != NULL);
なるほど余計なものがくっついてたら対象にならんわけだ (置換操作そのものは後続の部分でやっている)。
flag
で、上記のコードで出てきているJflag
という変数は
コマンドラインオプションのJオプションが指定されたかどうかのフラグ変数ではあるのだけど、
その名前はあまりにあまりではないかと思うのですが
(以前にもFreeBSDのほかのコードで見たような覚えも)、
freebsd-src/xargs.c at main · freebsd/freebsd-src
while ((ch = getopt_long(argc, argv, optstr, long_options, NULL)) != -1)
switch (ch) {
case 'E':
eofstr = optarg;
break;
case 'I':
Jflag = 0;
Iflag = 1;
Lflag = 1;
replstr = optarg;
break;
case 'J':
Iflag = 0;
Jflag = 1;
replstr = optarg;
break;
case 'L':
Lflag = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr)
errx(1, "-L %s: %s", optarg, errstr);
break;
case 'n':
nflag = 1;
nargs = strtonum(optarg, 1, INT_MAX, &errstr);
if (errstr)
errx(1, "-n %s: %s", optarg, errstr);
break;
case 'o':
oflag = 1;
break;
case 'P':
maxprocs = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr)
errx(1, "-P %s: %s", optarg, errstr);
if (getrlimit(RLIMIT_NPROC, &rl) != 0)
errx(1, "getrlimit failed");
if (maxprocs == 0 || maxprocs > rl.rlim_cur)
maxprocs = rl.rlim_cur;
break;
case 'p':
pflag = 1;
break;
case 'R':
Rflag = strtol(optarg, &endptr, 10);
if (*endptr != '\0')
errx(1, "replacements must be a number");
break;
case 'r':
/* GNU compatibility */
break;
case 'S':
Sflag = strtoul(optarg, &endptr, 10);
if (*endptr != '\0')
errx(1, "replsize must be a number");
break;
case 's':
nline = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr)
errx(1, "-s %s: %s", optarg, errstr);
break;
case 't':
tflag = 1;
break;
case 'x':
xflag = 1;
break;
case '0':
zflag = 1;
break;
case '?':
default:
usage();
いくら定義が freebsd-src/xargs.c at main · freebsd/freebsd-src にあるように
static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag;
bool/BOOL/booleanでないとはいえ
freebsd-src/xargs.c at main · freebsd/freebsd-src
if (!Iflag && Rflag)
usage();
if (!Iflag && Sflag)
usage();
if (Iflag && !Rflag)
Rflag = 5;
if (Iflag && !Sflag)
Sflag = 255;
if (xflag && !nflag)
usage();
if (Iflag || Lflag)
xflag = 1;
if (replstr != NULL && *replstr == '\0')
errx(1, "replstr may not be empty");
そのフラグ変数にそれと関係するパラメーター(整数値)を収めてしまうのは… (getoptのループのところでもいくつかのオプションで数値パラメーターの値を入れてますな)
あと、オプションに付随する引数から整数値に変換するのに strtonum/strtol/strtoul と混在しているのはいいんだろうか?🤔
一方 GNU findutilsのxargs ではどうかというと findutils/xargs.c at r4.4.2-aix · aixoss/findutils
while ((optc = getopt_long (argc, argv, "+0a:E:e::i::I:l::L:n:prs:txP:d:",
longopts, (int *) 0)) != -1)
{
switch (optc)
{
case '0':
read_args = read_string;
input_delimiter = '\0';
break;
case 'd':
read_args = read_string;
input_delimiter = get_input_delimiter(optarg);
break;
case 'E': /* POSIX */
case 'e': /* deprecated */
if (optarg && (strlen(optarg) > 0))
eof_str = optarg;
else
eof_str = 0;
break;
case 'h':
usage (stdout);
return 0;
case 'I': /* POSIX */
case 'i': /* deprecated */
if (optarg)
bc_ctl.replace_pat = optarg;
else
bc_ctl.replace_pat = "{}";
/* -i excludes -n -l. */
bc_ctl.args_per_exec = 0;
bc_ctl.lines_per_exec = 0;
break;
case 'L': /* POSIX */
bc_ctl.lines_per_exec = parse_num (optarg, 'L', 1L, -1L, 1);
/* -L excludes -i -n. */
bc_ctl.args_per_exec = 0;
bc_ctl.replace_pat = NULL;
break;
case 'l': /* deprecated */
if (optarg)
bc_ctl.lines_per_exec = parse_num (optarg, 'l', 1L, -1L, 1);
else
bc_ctl.lines_per_exec = 1;
/* -l excludes -i -n. */
bc_ctl.args_per_exec = 0;
bc_ctl.replace_pat = NULL;
break;
以下略
printf
ところで
printf x"%.s" {1..255} | xargs -I {} echo {}
というprintfコマンド(この場合はbashのビルトインコマンドのそれ?)の使い方が気になった。
パイプの前半部分のprintf x"%.s" {1..255}
で
255個ならんだx
をつくっているようなのだけど、
echo {1..20}
で
kbk@toybox4:/mnt/c/Users/kbk$ echo {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
という出力になるので(255はちょっと大きいので小さくした)、 printfには1から255までの数字列が渡される。しかし printfに対する書式文字列には 書式指定が一つしかない? 🤔
調べてみると、printfコマンドの書式指定文字列は必要があれば 繰り返し利用されるものだった(知らなかった…)
The format is reused as necessary to consume all of the arguments. If the format requires more arguments than are supplied, the extra format specifications behave as if a zero value or null string, as appropriate, had been supplied. The return value is zero on success, non-zero on failure.
GNU coreutilsにあるprintfのソースコード を見ると、先頭にこんなコメントがあった。
/* printf - format and print data
Copyright (C) 1990-2020 Free Software Foundation, Inc.
The ‘format’ argument is re-used as many times as necessary to convert all of the given arguments.
念のため opengroupからも
issue 6
The format operand shall be reused as often as necessary to satisfy the argument operands.
issue 7
he format operand shall be reused as often as necessary to satisfy the argument operands.
その他
よくよく見ればきちんと書かれてますな。
- 【 printf 】コマンド――データを整形して表示する:Linux基本コマンドTips(319) - @IT
- printf コマンド - IBM Documentation
- 8.4.25 printfコマンド(書式の引数を書式に従って変換し,標準出力に出力する) : JP1/Advanced Shell
- printf コマンド – フォーマット形式で文字列を表示 | Linuxコマンド.NET
- コマンド:printf: UNIX/Linuxの部屋
次にx"%.s"
の部分。
クォートの外に「はみ出ている」x
の意図がよくわからないけれども
まずは %.s
の部分に注目する。
あまり使ったことのなかった機能なので忘れていたけれども
(数値が省略されているせいもあったけど)、
printfの書式指定での一般的な機能を使っているのねこれ。
precision
or the maximum number of bytes to be written from a string in the s conversion specifier.
The precision shall take the form of a( ‘.’ ) followed by a decimal digit string; a null digit string is treated as zero.
%.s
というのは対応する文字列引数を最小幅0、最大幅0で出力させるというもので
結果として空文字列になる(精度の数値部分の省略は0を指定したのと同じ)。
kbk@toybox4:/mnt/c/Users/kbk$ printf "x%5.sx\n" hello
x x
kbk@toybox4:/mnt/c/Users/kbk$ printf "x%.sx\n" hello
xx
kbk@toybox4:/mnt/c/Users/kbk$ printf "x%5.5sx\n" hello
xhellox
kbk@toybox4:/mnt/c/Users/kbk$ printf "x%.4sx\n" hello
xhellx
また書式指定文字列の頭にくっついたxは
kbk@toybox4:/mnt/c/Users/kbk$ printf x"%s\n" hello
xhello
kbk@toybox4:/mnt/c/Users/kbk$ printf "x%s\n" hello
xhello
kbk@toybox4:/mnt/c/Users/kbk$ printf x%s"\n" hello
xhello
kbk@toybox4:/mnt/c/Users/kbk$
のようになるので(なんでクォートの外に?)、
x"%.s"
は書式指定以外のコマンドライン引数の数だけxを出力すると。
よくできてるなと思いつつもほかの手段はなかったのかと考えたり。
kbk@toybox4:/mnt/c/Users/kbk$ perl -E 'say "x" x 20'
xxxxxxxxxxxxxxxxxxxx
kbk@toybox4:/mnt/c/Users/kbk$ ruby -e 'puts "x" * 20'
xxxxxxxxxxxxxxxxxxxx
kbk@toybox4:/mnt/c/Users/kbk$ python -c 'print("x" * 20)'
xxxxxxxxxxxxxxxxxxxx
ただまあ、bashだと組込みでも持ってるくらいだしねえ printf。
あと、「はみ出ているx」については、 古より伝わるシェルスクリプトのワザの影響なのかも。 と思わないでもない。
test([
)コマンドの引数で string interpolationを使っているときに
結果が空になって構文エラーになるのを防ぐアレね。
追記(8/22
xを頭にくっつけるテクニックについて
- ちくパ — Bashでif文を記述する際にx"$var"と書く理由
- sh - if 文で [ “x$var” = “x” ] とする理由は? - スタック・オーバーフロー
- Bashスクリプトで「こいつ……できるっ」的なオーラを醸し出せるかもしれないTips | ハックノート
- What’s the purpose of adding a prefix on both sides of a shell variable comparison to a string literal? - Unix & Linux Stack Exchange
メモ
xargsとprintfを調べている途中で遭遇したもの。
Command-line interface - Wikipedia
CP/M typically used [.
CP/Mのオプション指定文字って/
でなかったの?
Argument Syntax (The GNU C Library)
25.1.1 Program Argument Syntax Conventions
getopt 以外に argp という解析関数があったのね。