-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
note.txt
9749 lines (7348 loc) · 572 KB
/
note.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding:utf-8 -*-
拡張
* プログラム補完に於いて、
補完関数内で compopt -o filter_by_prefix を指定した場合、
生成される候補を接頭辞が一致するものだけに絞り込む。
制限
* ble.sh を attach しているとき builtin read -e は動かない。
代わりに ble.sh が定義したシェル関数 read (組み込みコマンドを上書き)
を用いて read -e を呼び出す必要がある。
* bash-3 C-d について
今は何とか C-d を処理する事に成功しているが完全ではない。
1 C-d を押した時に bash が出力するエラーメッセージを使って捕捉している。
このエラーメッセージは言語や設定によって異なると思われる。
現在は以下のメッセージを調べている。
- 'Use "exit" to leave the shell.'
- 'ログアウトする為には exit を入力して下さい'
- 'シェルから脱出するには "exit" を使用してください。'
自分の bash が異なるメッセージを出力する時は
それを bleopt_ignoreeof_message に設定する。
2 連続で沢山 C-d を押すと "^D" が echo されて表示が乱れるかもしれない。
最悪の場合 C-d によって bash プロセスが落ちる可能性もあるかもしれない。
(未だ落ちた事はないが)。
3 C-d を処理する為に SIGUSR1 を使用している。
その為 SIGUSR1 を別の目的で使用する事は出来ない。
* 文字コードについて
現在は基本的に UTF-8 を想定している。
それ以外の環境のためには少なくとも以下の修正が必要になる。
- ble.sh 自体を iconv で変換する事。或いは日本語を完全に排除する事。
現在のところは日本語はコメント中にしか含まれていないはずである。
コメントさえ削除すれば何処でも動くようになっていると良い。
- 使いたい文字コード → unicode のデコーダを自分でかく事:
これは "function ble-decode-byte+文字コード" を実装すれば良い。
- Unicode → 文字のコードが正しく動作する様にする事:
これは .ble-text.c2s (ble-core.sh) の辺りを直せばよい。
"ble-text-c2b+文字コード"
"ble-text-b2c+文字コード"
も実装する必要がある。
- ble/encoding:$bleopt_input_encoding/generate-binder
現在 "C-@", "ESC" 及び "ESC *" を bind する為に、
その符号化形式の非正規な符号に変換している。
この変換はシェル関数 ble/encoding:$bleopt_input_encoding/generate-binder
において文字符号化方式毎に (UTF-8 前提の設定を上書きする形で) 定義する。
また bind を記録したキャッシュは $bleopt_input_encoding 毎に保持するが、
このキャッシュの更新は bind.sh のタイムスタンプしか見ていない (ble-decode/bind 内)。
新しい符号化方式を定義する時には、タイムスタンプを参照するファイル
(ble/encoding:$bleopt_input_encoding/generate-binder を定義するファイル) を決める必要がある。
他の文字コードは未だ一回も実装していないので上記以外にも必要な作業が出て来る可能性がある。
+ 2015-11-30 Note: ble-decode.sh (generate-source-to-unbind-default)
文字コード実装時に問題があるかも。
現在、bind -sp が出力する中途半端なバイトを解釈する為に、LANG=C で awk を起動している。
UTF-8 の場合には複数バイト文字を構成するバイトは ASCII 文字と被らないので問題ないが、
Shift_JIS 等の場合には ASCII 文字、特に \ や " を含む可能性がある。
この場合には LANG=C にしていると問題が生じる。
というか、bind -sp の出力する中途半端な文字と、複数バイト文字の一部を本質的に区別する方法はない様に思われる。
ただし、救いは、もし ble.sh を plain な bash の上で起動するとすれば
日本語で bind -sp に登録がなされていることはないだろうということである。
つまり、ユーザが手で (或いは .inputrc に) bind '"日本語":"にほんご"' などとしない限りは問題は生じない。
* bash-4.0, 4.1 において特殊シェル変数 FUNCNAME をユーザが unset した上で、
関数内から ble.sh を source すると ble の使う連想配列がローカルに定義され問題になる。
- bash-4.0 以降では連想配列を用いるが bash-4.2 未満では、
連想配列を明示的にグローバルに配置することができない。
- FUNCNAME がユーザによって削除されていなければ、
この変数を用いて関数内から source されたことを検知できるので、
その時には配列実装に fallback する。
FUNCNAME が削除されていると fallback に正しく切り替わらずに問題になる。
* bash-4.3 では C-x は、次の文字が来るまでは受信できない。
bash-4.0 - 4.4 の他の version では遅延はないのでこれは bash-4.3 特有の問題である。
* 構文に従った着色の中には bash の不自然な振る舞いや、
複雑な振る舞いのために正確さを諦めた物がある。
- bash の最初の [@()] の構文解析とパス名展開時の解析の齟齬
echo [@(echo|[...])]
恐らく bash は最初の単語の切り出しで @() を一単位として読み取り、
["@(echo|[...])"] の様に読み取る。その上で、改めてパス名展開を適用するが、
その時には ["@(echo|[.."]")]" の様に解釈する。
つまり、初めの構文解析とパス名展開の適用の間に齟齬がある。
ble.sh では構文解析に従った解析・着色をすることにしたので、
実際のパス名展開の適用結果が着色と異なることがあることに注意する。
- bash echo {@(,)}
これについても上と同様のことが起こる。
単語の切り出しは {"@(,)"} となり、構文エラーは発生しない。
後のブレース展開では {"@(",")"} と解釈されて分割される。
単語が分断されてしまうのでパス名展開は起こらない。
- bash のブレース展開時の ${var:-...}{,} の解析とパラメータ展開時の解析の齟齬
echo ${var:-{a,b}{a,b}
恐らく bash は最初にブレース展開を試みる時に、
${} の中については {} の入れ子を数えてスキップする。
従って、上のコマンドの時は ${} が終端しないのでブレース展開は試みられない。
しかし、パラメータ展開が実施される時には {} の入れ子は考慮に入れられず、
最初に現れた "}" で終端するので、${var:-"{a,b"}"{a,b}" という解釈になる。
[予定]
ble.sh ではどの様に着色するか微妙である。
理想的には最終的な解釈の ${var:-"{a,b"}"{a,b}" に応じた着色にしたいが、
後半の {a,b} の部分が {} の入れ子のアンバランスによって
無効化されている事を検出するのは困難である。
仕方がないので、ブレース展開の {} の入れ子の勘定はバグとして無視する事にする。
つまり、echo ${var:-"{a,b"}{a,b} という解釈で着色する。
- bash のチルダ展開の時の echo a[]b]=~ の解析と、パス名展開の時の解析
チルダ展開の時には a["]b"]=~ とはならず a[]"b]="~ という解釈になるので、チルダ展開は起こらない。
一方で、パス名展開のときには a["]b"]"=~" という解釈になり、'ab=~' などのファイル名に一致する。
ble.sh ではパス名展開の規則の方を優先させる。
- ble.sh では [[ @({a,b}) ]] のブレース展開が有効であるかの様に着色される。
実際には、条件コマンドの中ではブレース展開は無効になる。
これに正確に対応する為には "条件コマンドの中の extglob"
に対応する文脈値を定義する必要があるが、煩雑になるので対応していない。
- ble.sh では echo [{@(a|b),[abc]}] の内部の extglob や [...] が有効であるかの様に着色される。
しかし、実際にはブレース展開を実行したとしても [] の内部なので、
extglob や [...] は不活性化しているはずである。
しかし、これも解析が無意味に複雑になるので対応はしない。
- ble.sh では echo {~user,~user} の内部のチルダ展開に反応しない。
bash ではブレース展開された後にチルダ展開が実行されるので有効。
- ble.sh はブレース展開が含まれる変数代入形式単語でも、
ブレース展開より前のチルダ展開は有効である。
bash では変数代入形式の単語の右辺でチルダ展開が起こる。
しかし、ブレース展開が含まれている場合には例外としてチルダ展開が起こらない様だ。
$ a=~:{a,b}:~:echo → ブレース展開は起こらず、チルダ展開は起こる。
$ echo a=~:{a,b}:~:echo → ブレース展開が起こり、チルダ展開は起こらない
ble.sh では一つ目のチルダ展開の解析時点では、
次にブレース展開が来ることを知らないので、
一つ目の ~ はチルダ展開として着色する。
規則がよく分からないが、取り敢えず ble.sh ではブレース展開が現れたら、
それ以降はチルダ展開が無効になるようにしている。
具体的には _ble_syntax_bash_command_IsAssign[ctx] の設定されている文脈は、
ブレース展開が現れたときに、変数代入形式前の文脈値に戻すようにしている。
- echo [a[!b
echo [! の組み合わせは履歴展開にはならない。
echo [a[!b] の場合にも履歴展開にはならない。
しかし、echo [!a[!b の場合には履歴展開になる。
違いは bracket expressions が閉じているか閉じていないかである。
然し、それを判定する為には先読みをして単語の最後まで見ないといけない。
それは実装上困難なのでこれは諦める。
(bash の parser がここでどう動作しているのかは不思議ではある。
例えば echo [a[!echo""] は無効で [a[!echo"" は有効である。)
- echo $((echo)>/dev/null)
よく考えたらこの有名なパターンに対応するのを忘れていた。
- echo $(case A in A) echo B;; esac)
実はこのパターン。Bash-4.0 以降では大丈夫だが、
Bash-3.2 以降では構文エラーになる。ble.sh は bash-4.0 以降の振る舞いしかしない。
- ${#var[...]修飾}
この形式は Bash 的には構文エラーになるが、[...] の中身を相当先読みしないと
修飾があるかないかを見る事ができないので諦めている。
- set +H; echo ${!!修飾}
これは Bash では構文エラーだが何故かが分からない。
- {$v,$w}xxx これは $vxxx $wxxx に展開される。
つまり、v と xxx がくっついて新しい変数名になる。
これは分かりにくい動作だが、これを逆に使う人もあるのかもしれない。
実の所、ブレース展開も文法レベルで実施されるべきなのかもしれない。
* 2019-02-04 プログラム補完関数の中で標準入力は使えない。
どうしてもユーザからの入力を得たい場合には、
現在の補完が自動補完でない事を確認してから /dev/tty から直接取る事。
bash 実装上で注意するべき事
* 変数の代入は基本的に quote は必要ないが、
1 チルダで始まる時はチルダ展開を防ぐ為に quote が必要。
(変数展開の中にあるチルダは quote しなくても大丈夫)
2 配列要素を空文字列で連結するときは quote が必要。
つまり、IFS= eval 'declare var=${arr[*]}' とすると空白区切りになる。
IFS= eval 'declare var="${arr[*]}"' とする必要がある。
また IFS が中身のある場合には問題は起こらない。
- bash-4.3 以降では IFS= eval 'var=${arr[*]}' なら OK
関係あるか分からないが
http://lists.gnu.org/archive/html/bug-bash/2017-04/msg00001.html
において以下のような例が紹介されている。これは bash-4.5 で修正されるらしい。
| bash-4.2$ unset IFS; set ' '; a=$*; printf '<%s>' "$a"
| < >
| bash-4.3$ unset IFS; set ' '; a=$*; printf '<%s>' "$a"
| <>
* コマンドをつなぐ && と || の優先順位は同じで左結合である
但し、算術式や [[ ]] に登場する && と || はC言語と同じ優先順位である。
* unset の引数は quote しないとパス名展開の対象である。
特に配列要素を消す場合には [...] を quote する必要がある。
* unset -v または unset -f と明示的に指定しないと、
意図せず同名の関数または同名の変数を消去してしまう可能性がある。
変数を消す場合でも unset -v と明示する必要がある (ref #D0893)。
* コマンドの単語中のパラメータ展開は "" でクォートする必要がある
(ref #D0943)
特に値として以下の物が含まれている可能性がある時は絶対必要である。
先ず始めに IFS に含まれる文字がある場合は意図しない単語分割を抑制する為に "" で囲む。
次に、グロブの特殊文字 *?[ が含まれている場合にも注意する。
shopt -s extglob の時には @( や !( の並びにも注意する必要がある。
更に、'\' が含まれる場合もグロブ特殊文字のクォートに何故か影響を与える様なので注意する。
これは例えば shopt -s failglob において、a='\'; echo $a'*' がエラーメッセージを出す事で分かる。
[complete 仕様について]
* compgen -f はクォート除去、チルダ展開を実行する
理解できないのはクォート除去した後にチルダ展開をするという事。
compgen -f "'~/'" としても '~' というディレクトリには決して一致しない。
compgen -f "'\~/'" 等とクォートした上に backslash も指定しないと行けない。
結局どういう規則なのか分からないので、寧ろ arr=('~/'*) 等の様にするべき。
Note: ~ だとちゃんと現在のディレクトリ以下のファイルに一致するようだ?
Note: compgen -W でも似たような quote 除去・ブレース展開などを行う様だが、
それでも理解できる振る舞いになっている。
Note: bash --norc で echo \~/ から補完を実際に実行してみると echo ~/... に書き換わってしまう。
何処かで quote が消えてしまっている。これはバグと見做すべきであろう。
* $ complete -F foo -C bar command と登録すると foo, bar の両方が foo bar の順に実行される。
$ complete -C bar -F foo command と登録すると bar foo の順に実行される。
しかし、complete -p とすると両者とも
complete -C 'bar' -F foo
と表示され登録順・実行順についての情報を取り出す事ができない。
→今試すと必ず foo bar の順序でしか呼び出されない。compgen でも同様に見える。
* $ complete -F hoge1 -F hoge2 command とすると、-F hoge2 だけ有効になる
(complete -p による表示もそうだし、実際に実行されるのも hoge2 だけであった)。
-F オプションは後からものによって上書きされるという事の様だ。
* shopt -q は通常の出力はやめてもエラーメッセージは出す。
つまり未実装のオプション (compat* や autocd) について
shopt -q をするとエラーメッセージが出力されるので
結局 &>/dev/null にリダイレクトしなければならない。
* locale の環境変数 LC_*/LANG を設定する時は &>/dev/null する必要がある。
ref #D1205 #D1341 #D1355
元々入っていた値が不正な値である場合、
元の値を復元した時にエラーメッセージが意図されず出力される。
ローカル変数として設定する場合は、
- 値の復元はどうやら関数の本体を完全に実行し終わった後に起こる様なので、
関数の本体自体を &>/dev/null で囲んでも意味はない。
- 関数の中で unset を行っても意味はない。
- 関数の中でもとの値を設定しても意味はない。
関数が抜ける時に改めて設定される様だ。
IFS= LC_ALL=C read -t 0 &>/dev/null
としても復元時のメッセージは何故か抑制できなかった。
* #D1341 更に、bash-4.1 以下では LC_ALL= LC_COLLATE=C func 等の形式にしても
効果が現れない。local LC_ALL= LC_COLLATE=C としないと効かない様である。
外部コマンドを呼び出す時には問題は起こらない。関数経由でも大丈夫。
逆に外部コマンドの時には "LC_ALL=C awk" の形式にする必要がある。
もしくは "local -x LC_ALL= LC_COLLATE=C" とする。
ng$ aaa() { echo ${#1}; }; LC_CTYPE=C aaa あいうえお
ok$ echo あいうえお | LC_CTYPE=C awk '{print length($0)}'
ok$ echo あいうえお | LC_CTYPE=C ble/bin/awk '{print length($0)}'
* 2021-01-15 aaa() { local LC_ALL= LC_CTYPE=C; ... ; } 2>/dev/null の形式でも
駄目だという事が判明した。ちゃんとする為には関数内で unlocal までする必要がある?
* Bash 正規表現はシステムの <regex.h> を使用するので環境依存である。
Linux においては bash 正規表現の POSIX 文字クラス ([[:alpha:]] など) は
ロケールによって何にでも一致するので信用できない。
例えば GNU/Linux (Fedora 25) では ja_JP.UTF-8 で [[:alpha:]] は漢字・仮名にも一致する。
* bind 関数の中で set +o emacs などをして編集モードを無効にすると、
編集関数の実行自体が中断されるようである。
具体的には set +o emacs を含む行だけ実行されて、次の行以降は実行されない。
set +o emacs が eval に含まれる場合は eval が終わると共に中断される。
また関数内に set +o emacs がある場合は、その関数は最後まで実行されるようだ。
従って set +o emacs が実行されたことを検知して適切な後処理を実行するのは難しい。
更にその後で set -o emacs に戻ってくると変な状態になる。
bind -p ではちゃんと hook された状態になっているが、
実際に操作してみると keymap はリセットされているように見受けられる。
この辺りはもう少し詳しく調べてみないと具体的に何が起こっているかはわからない。
例: 以下の3行のコマンドを実行しようとすると途中で中断され元の状態には戻らなくなる。
$ set +o emacs
> echo hello
> set -o emacs
直接 readline で実行している場合にはこの問題は起こらない。
* ble.sh では変数の -i は積極的には使用しないことにした ref #D0894
関数引数に使用する場合は、そもそも -i の機能を使う機会の方が少ないので
全ての関数の引数に適用するのは非効率であり、一部の関数の引数にだけ適用するのは
関数の仕様として分かりにくくバグの元である。そもそも算術式展開が必要化どうかは
呼び出し元が知っていることのはずなので呼び出し元で算術式展開をするべきである。
関数内で使用する場合についても明示的に算術式展開を実行すれば良い。
* bind 関数中の set +v は揮発性 ref #D0930 (Bash 3.0--5.0)
bind 関数中で set +v 等としてもその状態は
次の bind 関数の呼び出しの際には元に戻ってしまう。
この振る舞いは試した全ての bash version で共通だった。
bashbug: 実装上で注意するべき事・バグ
* bash-5.0 -- 4.4 (ref #D1334)
trap handler が実行中に return を無引数で呼び出すと、
無条件に trap handler 起動直前の $? が関数の終了ステータスになる。
POSIX に要求されていると書かれているが解釈に難がある。
特に trap handler を抜ける時の戻り値だけに影響を与えるのが自然に思われる。
* bash-5.0 -- 3.0 (全 version) バグ (ref #D0943)
$ shopt -s failglob
$ a='\'; echo $a'*'
これで failglob になる。\* に一致するファイルは存在しませんのエラーメッセージ。
ファイルとして '*', '\*', '\a', 'a' 等があっても決して一致しない。
これを防ぐ為には、パラメータ展開は必ず "" でクォートする様にすれば良い。
* bash-5.0 -- 3.0 (全 version) バグ
history -p をコマンド実行中に呼び出すと呼び出す度に履歴項目が減る。
これは例えば f1() { history | tail -1; history -p '!!'; history | tail; } として、
f1 を実行すると分かる。f1;f1;f1 等とすると一回で3件消える。
更に bash-3.0 では bind -x の関数の中であっても history -p を呼び出す度に履歴項目が減る。
* bash-4.4 -- 4.3 バグ
\C-@ 関係に bind -x すると正しく動かない
bash-4.4 での動作については未だ確認していない。
→ bash-4.4 でもやはり動かない。
これは修正した http://lists.gnu.org/archive/html/bug-bash/2018-03/msg00165.html
* bash-4.4 -- 3.2, etc
rex="^([^\$]|\\'[^\\']*\\')+\$" && [[ 'i$' =~ $rex ]] && echo hello
が一致する。\' の解釈が謎である。単に ' とすれば問題ない。
rex=$'^([^$]|\\\'.\\\')+$' でも一致する。
rex=$'^([^$]|\\\')+$' だと一致しない。
\' は何らかのアンカーとして解釈されるという事だろうか。
或いは単純に無視されているのか。
* bash-4.2
declare -g -r var とした時に、
グローバル変数が定義されていなければローカルに新しく変数を作る様だ。
bash-4.3 で直っている。
* bash-4.2 以下
bash-4.2 ~ bash-3.0
\C-x 単体に bind -x して C-x に続けて何か打つと segfault する。
$ bind -x '"\C-x":echo' → 続けて C-x a 等と入力
* bash-4.1 以下: LC_CTYPE=C eval 'echo ${#var}' としても
${#var} が元のロケールで計算される。"変数代入 コマンド"
の形式だとロケールの初期化が間に合わないのだろうか。
* bash-4.0 segfault
以下で segfault を起こすことが分かった。bash-4.1 以降では直っている。
bash-4.0 -c 'function f1 { COMPREPLY=(alpha); }; compgen -F f1 2>/dev/null'
但し、ble.sh の使用中に実際に compgen -F を通して segfault になることはなかった。
もしかすると何らかの条件が整うと segfault するかもしれないので、
念のためここに記録に残しておく。
* bash-4.0 -- 3.0
$'' 内に \' を入れていると履歴展開が '' の中で起こる?
例えば rex='a'$'\'\'''!a' とすると !a の部分が展開される。
* bash-3.2 以下ではプロセス置換に含まれるブレース展開は
プロセス置換ごと複製してしまう。
例えば echo <(echo {1..3}) は、
echo <(echo 1 2 3) ではなくて、
echo <(echo 1) <(echo 2) <(echo 3) に展開されてしまう。
* bash-3.2 以下では declare a としただけで空の値で初期化される。
unset 状態になるという事はないので注意を要する。
* bash-3.2, bash-3.1 では source にプロセス置換を渡しても読み取ってくれない。
つまり source <( ... ) としても何も起こらない。
代わりに eval -- "$( ... )" すると良い。
* bash-3.2 -- 3.1
ref #D0857
10 以上のファイルディスクリプタで使用されている物に対して
リダイレクションで新しい出力先を設定しようとしても失敗する。
これは fd>&- として一旦閉じてからリダイレクションすれば良い。
bash-3.1 では一度開いた fd を改めて開き直したり、
或いは閉じたりすることができない。
exec 34>/dev/null とすると、exec 34>&- としても閉じれないし、
exec 34>a.txt としても /dev/null に繋がったままになってしまう。
* bash-3.1 では a=(""); echo "a${a[*]}b" | cat -A とすると
a^?b となって謎の文字が入る。echo "a""${a[*]}""b" 等とすれば大丈夫。
* bash-3.1 では declare -f funcname の funcname に + 等の文字を含める事ができない。
一応 declare -F 等とすれば名前は列挙される様ではある。
bash-3.2 未満では declare -f ではなく type -t で関数かどうかの確認を行う。
* bash-3.1 での bind -r について
bind -sp とすると "\M-[C" 等と表示されるがそれに従って bind -r '\M-[C'
としても削除する事は出来ない。代わりに bind -r '\e[C' とすれば削除できる。
eval -- "$(bind -sp | awk '/M-\[/{sub(/:$/,"",$1);gsub(/\\M-/,"\\e");print "bind -r " $1}')"
* bash-3.1
呼出先の関数で、呼出元で定義されているのと同名の配列を作っても、中が空になる。
> $ function dbg/test2 { local -a hello=(1 2 3); echo "hello=(${hello[*]})";}
> $ function dbg/test1 { local -a hello=(3 2 1); dbg/test2;}
> $ dbg/test1
> hello=()
これは bash-3.1-patches/bash31-004 で修正されている様だ。
* bash-3.1
- ${#arr[n]} は文字数ではなくバイト数を返す様だ。
- "${var//%d/123}" は動かない。"${var//'%d'/123}" 等とすればOK。
- bash-3.0, bash-3.1: local GLOBIGNORE すると、
関数を出てもパス名展開の時にその影響が残っている。
(直接変数の中身を見ても何もない様に見えるが。)
unset GLOBIGNORE などとすると直る。
* bash-3.0
- ${#param} は文字数ではなくバイト数を返す、という事になっているらしいが、
実際に試してみると文字数になっている (bash-3.0.22)。
何処かで patch が当たったのだろうか。まあいいか…。
(※${param:ofs:len} は 3.0-beta1 以降であれば文字数でカウントされる)
- declare -p A で改行を含む変数を出力すると改行が消える。
例: 一見正しく出力されている様に錯覚するが "\ + 改行" は改行のエスケープではなく、
長い文字列リテラルを二行に書く為の記法である。つまり、無視される。
$ A=$'\n'; declare -p A
| A="\
| "
* msys1, msys2: var='^M' とすると CR が消えてなくなる。
msys2 では var=$'\r' とすれば大丈夫。また変数に入っている物も大丈夫。
例えば var=$_ble_term_CR はOKである。
msys1 ではそれでも駄目。local var=$'\r' とすれば大丈夫。
変数に入っている物でも local を付けないと消滅してしまう。
* msys1 では named pipe が未対応。従ってプロセス置換も使えない。
bashbug 算術式周りのバグと注意点
* bash-3.0 - 4.4.7 算術式:
条件分岐で実行されない部分でも配列の添字は 0 以上でなければならない。
例えば以下はエラーになる @ bash-3.0, 3.1, 3.2, 4.0, 4.2, 4.3
((a=-1,a>=0?b[a]:0))
もっと調べてみると配列の添字に限らず分岐しない所で式が評価されている様だ:
+ 三項条件式で起こる。true/false branches のどちらでも起こる。&& や || では起こらない。
$ echo 'x=a=1; ((a=0,0?x:0)); echo $a' | bash 1 (bash-3.0 - 4.3)
$ echo 'x=a=1; ((a=0,1?0:x)); echo $a' | bash 1 (bash-3.0 - 4.3)
$ echo 'x=a=1; ((a=0,0&&x)); echo $a' | bash 0 (bash-3.0 - 4.3)
$ echo 'x=a=1; ((a=0,1||x)); echo $a' | bash 0 (bash-3.0 - 4.3)
$ echo 'x=a=1; ((a=0,0?b[x]:0)); echo $a' | bash 1
$ echo 'x=a=1; ((a=0,0&&b[x])); echo $a' | bash 0 (bash-3.0, 3.1, 4.2+ / bash-3.2, 4.0, 4.1 は別の bug で 1)
+ 括弧で囲めば何も起こらない様だ。
$ echo 'x=a=1; ((a=0,0?(x):0)); echo $a' | bash 0 (bash-3.0 - 4.3)
$ echo 'x=a=1; ((a=0,1?0:(x))); echo $a' | bash 0 (bash-3.0 - 4.3)
$ echo 'x=a=1; ((a=0,0?(b[x]):0)); echo $a' | bash 0 (bash-3.0, 3.1, 4.2+ / bash-3.2, 4.0, 4.1 は別の bug で 1)
* bash-4.2 算術式 seg fault
https://lists.gnu.org/archive/html/bug-bash-gnu/2013-01/msg00036.html
https://lists.gnu.org/archive/html/bug-bash-gnu/2013-01/msg00042.html
https://lists.gnu.org/archive/html/bug-bash-gnu/2013-01/msg00043.html
算術式の中で配列要素の参照に関係して特定の式構造になると segfault する。
多分、配列要素の読み出しの次の token が整数または代入式の左辺だと落ちる。
配列要素を参照したら一旦算術式を閉じるのが良い。
$ ((a=b[0],c=0))
以下でも segmentation fault が起こった。
$ (((klen=node[nofs+k])<0||(kbeg=j-klen)>end0))
$ (((a=node[1])<2||(b=3)))
$ (((a=node[1])||(b=3)))
$ (((a=node[1])<2||b)) # OK
$ (((a=node[1])||b)) # OK
$ (((node[1])||(b=3))) # OK
やはり起こる条件が良く分からない。
代入式の右辺に配列が来て、
その後に代入式の左辺に token があると駄目なのか?
* bash-4.1, 4.0, 3.2: 算術式分岐内配列参照
bash-3.2.48 で以下の評価に失敗する。
bash-3.1 以下は大丈夫。bash-4.2, bash-4.3 も大丈夫。bash-4.0 は駄目。
dbg=()
((a=0,b=0,0&&(a=1,x=dbg[0],b=1))) # NG
配列添字で値を参照 (代入はOK) すると、その部分以降が必ず実行される。
複合代入であっても駄目である。
bash-4.0 bash-4.1 でも以下の式で必ず _pos[1]++ が実行されていた。
((_eoc[2]&&(_pos[0]=0,_pos[1]++)))
$ ((a=0,b=0,0&&(a=1,x=dbg[0],b=1))); echo $a $b → 0 1
$ expr="a=1,x=dbg[0],b=1"; ((a=0,b=0,0&&expr)); echo $a $b → 0 1
$ expr="a=1,x=dbg[0],b=1"; ((a=0,b=0,0&&(expr))); echo $a $b → 0 1
更に配列添字も必ず評価されてしまう。
((i>=0&&a[i])) は i が負であっても参照される。
そして、((i>=0&&a[i--])) をすると更に副作用も起こる。
* bash-4.1 以下 (bash-3.0 ~ bash-4.1)
配列要素に対して修飾付きのパラメータ展開を実行すると、
配列添字に指定した算術式が2回評価される。
例えば "${arr[i++]#a}" を実行すると i が 2 増える。
* bash-4.0 他 算術式を使って値を計算する時の注意
算術式の中に初期化されていない変数…例えば ret 等がある場合、
ret の中身に不正な数式的な物が入っていたりコマンド置換が入っていたりすると、
文法エラーになったりこれが eval されてしまう。
実際に 4.0 では 'あ' という文字列が入っているだけでエラーになる。
(より上の version では識別子名と解釈されているからなのかエラーにはならない。
しかし、今迄は毎回「あ」等という変数を探していたのだろう。
* bash-3.1, 3.0
?: 演算子の中身は全てカッコで囲まないと構文エラーになる。例えば、
$ bash-3.1 -c '((a?(b=123):c?(d=321):1))'
bash-3.1: ((: a?(b=123):c?(d=321):1: syntax error in expression (error token is "?(d=321):1")
bash 配列の宣言に関する仕様・バグと注意点
* arr=(1 2 3) func の形式で配列をシェル関数に渡そうとすると、
export arr='(1 2 3)' で渡されてしまう。
* 既に配列変数になっている物に対して
export var=value や typeset -x var=value をしても、
呼び出された別コマンドからは環境変数として見えない。
$ a=(1 2 3)
$ (export a=1; bash -c 'declare -p a')
bash: 0 行: declare: a: 見つかりません
新しい変数として導入すれば良い。
例えば関数内で新しく local -x var=value とするか、
var=value command の形式で呼び出すようにすれば良い。
$ (a=1 bash -c 'declare -p a')
declare -x a="1"
* BUG bash-4.0, 4.1 (local), bash-3.0 ~ 3.2 (declare)
a[${#a[*}]=value もしくは ble/array#push a value するとき、
その配列を事前に宣言したければ local -a a のように -a を指定する必要がある。
[問題]
bash-4.1 以下で関数内で local arr しただけで ${#arr[*]} が 1 になる。
その後、要素 #1 を設定しても ${#arr[*]} は 1 のままである。
これの所為で以下のコードが破綻する:
arr[${#arr[*]}]=...
常に要素 #1 にしか代入されない事になる。
bash-3.2 以下では関数内に限らず declare arr しただけで ${#arr[*]} が 1 になる。
但し、要素[1] に設定をすると ${#arr[*]} は 2 に増加する。
従って余分な空要素があるものの ble/array#push は失敗しない。
[解決]
local -a arr とすれば問題は起きない。
※local arr=() としても問題は起きないがこの記述だと
今度は bash-3.0 で文字列 '()' が代入されて問題である。
* BUG bash-3.0: local a=(...) や declare a=(...) とすると、a="(...)" と同じ事になる。
a=() の形式ならば問題ない。
* BUG bash-3.0: 今まで local -a a=() の形式ならば問題ないと信じてきたが、どうやら
local -a a=('1 2') が local -a a=(1 2) と同じ意味になってしまうようだ。
a="123 345"; declare -a arr=("$a"); このようにしても駄目だ。
a="123 345"; declare -a arr; arr=("$a"); こうする必要がある。
* 配列要素を連結する時
動く例:
IFS= eval 'value=${arr[*]}'
IFS= eval 'value="${arr[*]}"'
IFS= eval 'local value="${arr[*]}"'
動かない例 (間に空白が入ってしまう):
IFS= eval 'local value=${arr[*]}'
* BUG bash-4.0..4.4: ローカルで local -a x; local -A x とすると segfault する。
ref http://lists.gnu.org/archive/html/bug-bash/2019-02/msg00047.html, #D0924
f() { local -a a; local -A a; }; f # これで segfault する
- 別のスコープで定義された配列を -A とした場合には起こらない。
- 同じスコープの場合でも unset a してから local -A a すれば大丈夫。
- グローバルでは起こらない。
* BUG bash-3.0..3.2: ^? や ^A の値が declare -p で ^A^? や ^A^A に変換されてしまう。
bash_features
* time -- について。
bash-5.1 以降で time -- command が可能。
bash-4.2 以降で time -p -- command が可能。
(bash-4.1 以前では time には -- を指定できない)
* bash-5.0 以降: EPOCHREALTIME, EPOCHSECONDS
ref #D0925
* Bash-5.0 では POSIX に倣ってパラメータ展開結果に \ が含まれる場合に
グロブパターンと見做す様に変更されたが、
これにより問題が起こり POSIX が記述に誤りがあることを認めて修正した。
結局 Bash-5.1 で 4.4 と同じ動作に戻すつもりらしい。
https://lists.gnu.org/archive/html/bug-bash/2020-03/msg00051.html
* ${param@a} (attributes) 及び他の transformation は bash-4.4 より
* read -t timeout
* -t オプションの対応は 2.04 である。
* TMOUT 変数の対応は 2.05b-alpha1 以降である。
* 小数を指定できる様になったのは 4.0-alpha 以降である。
* `-t 0' で次の文字を読み取り可能かどうかチェックできるのは 4.0 以降である。
* 4.3 以下では timeout した時に読み取った入力は失われてしまう。
4.4 以降では timeout するまでに読み取った内容が指定した変数に格納される。
* グローバル変数に対する属性指定 declare -g は bash-4.2 から
更に bash-4.3 には declare -gA を二度行うとクラッシュするバグがあったらしい。
現在の最新版ではそのような振る舞いは見られない?
2021-02-10 #D1470 どうも bash-4.2 の declare -g にはバグがある。declare -gA
とすると属性は global まで適用されるが、代入された値は関数を抜けると共に消
滅する。
* 連想配列 declare -A は bash-4.0 から
* BASHPID 何と Bash 4.0 以降の機能らしい ref #D1200
------------------------------------------------------------------------------
This document details the changes between this version, bash-4.0-alpha,
and the previous version, bash-3.2-release.
c. There is a new variable, $BASHPID, which always returns the process id of
the current shell.
------------------------------------------------------------------------------
と思ったら既にソースコードの一部にも Bash 4.0 以降であるとの注記があった。
* command |& command は Bash 4.0 以降なので使えない。
* printf -v var %s value
bash-3.1 以降で使える。
bash-4.1 以降で var として配列要素 (arr[123] 等) を指定できる。
* ${!arr[@]} は bash-3.0 より
bash_tips
* swap の仕方
local a=$b b=$a
local や declare などは必要である。
* [[ ]] の中で =~ で設定された BASH_REMATCH は直後の式で参照できる。
つまり [[ $text =~ $rex && $BASH_REMATCH == ... ]] の様にできる。
bash-3.0 から bash-4.4 までで以下のコマンドで確かめた。
[[ "" =~ ^ ]]; [[ $BASH_REMATCH ]]; [[ a =~ a && $BASH_REMATCH ]]
* 構文関係でマニュアルに載っていないものが色々ある。
* }, fi, done, esac の直後に }, fi, done, esac, do, else, elif, then が来る場合はセミコロンは省略できる。
* for ((expr1; expr2; expr3)) [ ; ] { list; } は比較的有名だが、
for name [in name]; { list; }
select name [in name]; { list; } も使える様だ。
* select name [ [ in word ... ] ; ] do ...; done
※in word ... がない場合、do の前のセミコロンは省略可能である。
* "$(case *) ;; esac)" に対応する可能性があるかと思ったが動きはない
ref http://lists.gnu.org/archive/html/bug-bash/2017-11/msg00002.html, #D0928
* function @() { ...; } は成功するが実際には関数は作られない
ref http://lists.gnu.org/archive/html/bug-bash/2017-03/msg00220.html, #D0927
* declare -c var という隠し属性がある。Capitalize する。Bash 4.0+
変数の値の各単語について適用するのではなく本当に最初の文字にしか適用されない。
この中途半端な機能の為に恐らくマニュアルに載っていないのだろう。
ソースコードを確認すると他にも declare -G var という謎機能が存在する。
同じ文脈に局所変数があればそれに設定してそれ以外ならば大局変数に設定する。
これは丁度他の言語のレキシカルスコープを真似た物という事だろうか。
* nameref & extra expansion
気付いたのだが declare -n ref='arr[...]' の ... に任意の式を記述できる。
これによって新しい乱数変数も定義できるのでは。例えば。
declare -n var='var_[var_=RANDOM*RANDOM,0]'
但し、算術式なので整数以外は代入できない。
更に、$() でプログラムを実行することすらできる。
然し、任意の文字列という訳には行かないのが問題。
$() はサブシェルで実行されるので副作用を残す事ができない。
* let & brace expansion
これは算術式のページに既に書いた。
* rcfile を処理している間は
* 関数内で FUNCNAME, BASH_SOURCE, BASH_LINENO を確認するとFUNCNAME
の最後の要素は "source" であり、BASH_LINENO の最後の要素は 0 に
なっている。BASH_SOURCE の最後の要素がファイル名である。
* bash-4.4 以降では $- に s (標準入力から読み取り中) が含まれない
事で確かめられる。bashrc を抜けてPROMPT_COMMAND を実行する時には
s が含まれる様になる。bash-4.4 未満では s は決して含まれない事に
注意する。
まとめると以下の様な関数で rcfile 中で走っているかどうかを判定できるのではないか。
function ble/util/is-running-in-rcfile {
[[ $- == *i* && ( _ble_bash -lt 40400 || $- != *s* ) ]] || return 1
local nstack=${#BASH_LINENO}
[[ ${BASH_LINENO[nstack-1]} == 0 && ${FUNCNAME[nstack-1]} == source ]]
}
*******************************************************************************
Memo
-------------------------------------------------------------------------------
2021-05-03
* awk の互換性に関する注意点 [#M0019]
* 正規表現 {m,n} は gawk-4 以降でしか既定で使えない。gawk-3 も nawk も mawk
も駄目。
POSIXに反しているが過去の互換性の為という事らしく gawk-3 では
POSIXLY_CORRECT またはオプション --posix または --re-interval を指定すれ
ば利用できる様になるが、nawk/mawk はそういうオプションすらない。
* 正規表現 A?A? は mawk では最初の A? しか一致しない。
これは明らかにバグの気がするがどうなのだろうか。
* 16進リテラル 0xHHHH は gawk でしか使えない。
2021-05-01
* ble.sh 初期化時の Bash 設定に対する対策 [#M0018]
ble.sh が set -euxv -o posix や FUNCNEST=0 等特殊な状況で呼び出される事がある。
この様な環境ではまともに動作する事ができないので設定を適切な順序で解除してい
く必要がある。
set -eu に関しては適切な記述方法を取れば回避する事ができるので後回しにする。
set -xv に関しても標準エラー出力を適当な物に繋いで置けば回避できる。set -o
posix が設定されていると関数を定義できない。その他の振る舞いにも注意が必要だ
ろう。alias も何が定義されているか分からないので出来るだけ expand_aliases を
off にする方向で考えたい。
現在の実装では以下の順にチェック・対策を行っている。
1 最初の引数解析 (POSIX shell 準拠): この部分は別のシェルで起動した場合などで
も引数解析の結果などを表示する為に対策よりも前に処理する。alias で { や if
が書き換えられている事によって失敗しても、シェルが全く操作できなくなるとい
う事はないだろうし、ユーザー側の責任とする。
2 Bash のバージョンチェック。これをしないとそもそも対策コード自体動くか怪しく
なってくるので先にチェックする必要がある。これもシェルが全く操作できなくな
るという事はないだろうという事で、ユーザー側の責任とする。
3 expand_aliases
4 FUNCNEST
5 set +o posix
この三つを設定すれば取り敢えず安全に関数を定義して実行できる。
6 reset-builtins
builtin が上書きされてしまうのを防ぐ為。
7 adjust-options (set +euxv; shopt -u nocaseglob; shopt -u expand_aliases)
2020-05-11
* Bash の HISTTIMEFORMAT 振る舞いのまとめ [#M0017]
ref #D1351
* Bash は、HISTTIMEFORMAT の値に関係なく、コマンドの時刻を常に内部
的に管理している (#0x10 の件を考えると文字列で記録している疑いが
ある)。HISTTIMEFORMAT が設定されている時、history コマンドで出力
されるコマンド履歴に時刻が出力される。
* 変数 HISTTIMEFORMAT が存在する時 (空文字列や unset も含む)、Bash
は履歴ファイルに #%s の形式で時刻を保存する。
* 履歴ファイルからコマンドを読み取る時、直前に #%s があればそれを
コマンドの時刻とする。それ以外の時はコマンドの時刻は bash の起動
時刻とする。これは HISTTIMEFORMAT の状態に関係ない。
履歴ファイルから読み取る時には単一行モードと複数行モードがある様
だ。変数 HISTTIMEFORAMAT が存在 (空文字列や unset も含む) してか
つファイルの先頭行が #%s の時に複数行モードになる。
時刻行は "#数字" で始まっているかどうかで判定する。先頭または #
と数字の間に余分な空白が含まれている場合は時刻行ではない。"#整数
" の後に別の文字列があったとしてもそれは無視される。但し、"#0"
で始まっている時だけは行全体を時刻と見做すようで、余分な文字列が
あると history で出力する際にエラーになる。
* history コマンドの出力は HISTTIMEFORMAT が非空文字列の時にタイム
スタンプが出力される。
HISTTIMEFORMAT が設定されていても空文字列の時には処理は行われな
い。これは通常の見た目の振る舞いでは区別がつかない (処理していて
も処理していなくても出力に違いは出ない) が、履歴ファイルに #0xxx
の様な無効なタイムスタンプが含まれていた時の振る舞いで分かる。
* shopt -s lithist は、for 等の文法的に複数行に跨るコマンドについ
て、そのままの形でコマンド履歴に登録する。単にコマンドラインで複
数行を入力して実行しても改行で分割してコマンド履歴に登録される。
これはコマンドを実行した時に Bash プロセスの内部のコマンド履歴に
登録する際に影響を与える物であって、履歴ファイルへの書出しや履歴
ファイルからの読み出しには影響を与えない様である。
現在の ble.sh サポートの制限について。
* mlfix: bash-4.4 以降では複数行コマンドを history -r で読み出せるが、
bash-4.3 以前では複数行コマンドは history -s で構築せざるを得ない。
従って複数行コマンドに関しては正しくコマンド時刻を復元できない。
2020-05-06
* trap: DEBUG/RETURN trap のまとめ [#M0016]
DEBUG trap は設置した関数内で有効。set -o functrace (set -T) が設
置されている時または呼び出される関数に declare -tf を設定している
時にのみ呼び出される関数に継承される。trap -p の出力は現在処理して
いる関数毎に異なる (継承しない場合は DEBUG/RETURN trap に対しては
何も出力されない)。
DEBUG: bash-4.3 以下では設置した関数の呼び出し元には影響はないが、
bash-4.4 以降では呼び出し元の DEBUG trap も上書きする。DEBUG trap
を削除した場合には、呼び出し元には影響は与えない。DEBUG trap の中
では DEBUG trap は発火しない。
RETURN:
* BASH_COMMAND には最後に関数内で実行したコマンドが入っている。
return を使った場合にはそれが、関数の末端で終わった場合には最後
のコマンドが入っている。
* RETURN trap は関数内部で実行されるので、return を呼び出して終了
ステータスを変更する事ができる。但し、条件をつけないと、RETURN
trap の return に対して再び RETURN trap が発火して無限ループにな
るので注意する。
* RETURN trap の中では RETURN trap は発火しない。それ以外の trap
では発火する。
BASH_LINENO, BASH_SOURCE, FUNCNAME についてはまだ詳しく調べていない。
2020-04-14
* ${###} 等のパラメータ展開・変数展開について [#M0015]
Bash のパラメータ展開 #D1330
<param>
- 位置パラメータ: 1 2 ...
- 特殊パラメータ: * @ # ? - $ ! 0 _
- 変数名: /_[[:alpha:]][[:alnum:]]*/ の形式
- 配列名[添字]
添字はシェル展開の対象で配列の時は算術式の対象
- 配列名[@], 配列名[*]
<modifier>
- @A 変数の定義
- @a 変数の属性
- @Q @E @P 値を加工する
これらの ops は展開の対象ではない。つまりvar=A として ${xxx@$var} とはできない。
- #, ##, %, %%
- /, //, /#, /% (クォートとの兼ね合い)
- ^ ^^ , ,, ~ ~~
Note: ~ については https://qiita.com/t_nakayama0714/items/80b4c94de43643f4be51 に書いてあった。
- = + - ? := :+ :- :?
- :offset, :offset:length
* $<param>
Note: 配列, 2桁以上の位置パラメータは使えない。
* ${...} の例外規則
* ${#<param>}
${#@}, ${#*}, ${#a[@]}, ${#a[*]} は要素の数。
それ以外については文字の数。
* ${!var@} ${!var*}
* ${!arr[@]} ${!var[*]}
* ${<param><modifier>}
* ${!<param><modifier>}
* ! で始まる物については ${<param>} を変数名とする。
Note: <param> は !, $ 以外でなければならない様だ。
$@ $* ${arr[@]} ${arr[*]} の時には "$*" などを変数名と見做す。
つまり、普通に ${!arr[*]##} 等とすると要素が1個の時以外はエラーになる。
(arr=(a b c); IFS=; abc=4321; echo "${!arr[*]##}") 等とすると動く。
(arr=(a b c); IFS=; abc=4321; echo "${!arr[@]##}") は動かない。
★${!#} で最後の引数を取れる。${@:$#} でも行ける。
但し、引数がない場合は $0 に展開される事に注意する。
2020-04-07
* bashrc に於ける history の操作について [#M0014]
初回の history -nrs の実行時に "未初期化" であれば初期化を行う。