Alfredのワークフローなどで、スクリプトにzshをはじめました。初心者用にメモを残します
シェルスクリプトで文字列の一部を取り出す
文字列の一部を取り出すというのは、エクセルVBAのmid関数みたいな操作のことです
シェルスクリプトのパラメータ展開というものを利用します
書式
${パラメータ:開始位置:長さ}
例
#日付の形式を変換する mmddyy → yyyy/mm/dd
mmddyy='031122';echo 20${mmddyy:4:2}/${mmddyy:0:2}/${mmddyy:0:2}
#→ 2022/03/11
※開始位置は先頭が0となります
※長さを省略すると文字列の最後まで切り取ります
雑談
開始位置や長さにマイナスが指定できるようなので、取りうる範囲を試してみました
※以下の例で結果表示としてパラメータにリテラル"ABCED"を指定していますが、本当は変数でないとエラーになります
開始位置がゼロ及び正の整数、長さが正の整数の場合
#開始位置が0及び正の整数、長さが正の整数
str=ABCDE; for i in {0..4}; for j in {1..$((5-$i))}; do echo '${"ABCDE":'$i':'$j'}='${str:$i:$j} ; done
#→ ${"ABCDE":0:1}=A
#→ ${"ABCDE":0:2}=AB
#→ ${"ABCDE":0:3}=ABC
#→ ${"ABCDE":0:4}=ABCD
#→ ${"ABCDE":0:5}=ABCDE
#→ ${"ABCDE":1:1}=B
#→ ${"ABCDE":1:2}=BC
#→ ${"ABCDE":1:3}=BCD
#→ ${"ABCDE":1:4}=BCDE
#→ ${"ABCDE":2:1}=C
#→ ${"ABCDE":2:2}=CD
#→ ${"ABCDE":2:3}=CDE
#→ ${"ABCDE":3:1}=D
#→ ${"ABCDE":3:2}=DE
#→ ${"ABCDE":4:1}=E
このパターンは直感的にわかりやすいですね
開始位置が負の整数、長さが正の整数の場合
# 開始位置が負の整数、長さが正の整数の場合
str=ABCDE; for i in {-5..-1}; for j in {1..$(($i*-1))}; do echo '${"ABCDE":'$i':'$j'}='${str:$i:$j} ; done
#→ ${"ABCDE":-5:1}=A
#→ ${"ABCDE":-5:2}=AB
#→ ${"ABCDE":-5:3}=ABC
#→ ${"ABCDE":-5:4}=ABCD
#→ ${"ABCDE":-5:5}=ABCDE
#→ ${"ABCDE":-4:1}=B
#→ ${"ABCDE":-4:2}=BC
#→ ${"ABCDE":-4:3}=BCD
#→ ${"ABCDE":-4:4}=BCDE
#→ ${"ABCDE":-3:1}=C
#→ ${"ABCDE":-3:2}=CD
#→ ${"ABCDE":-3:3}=CDE
#→ ${"ABCDE":-2:1}=D
#→ ${"ABCDE":-2:2}=DE
#→ ${"ABCDE":-1:1}=E
マイナスにすると末尾からのオフセットとなります
先頭位置の指定は先頭から0、1、2・・・ですが
末尾からの指定の場合は、末尾から-1、-2、-3となります
長さがゼロの場合
#長さがゼロの場合
str=ABCDE; for i in {-5..4}; do echo '${"ABCDE":'$i':0}='${str:$i:0} ; done
#→ ${"ABCDE":-5:0}=
#→ ${"ABCDE":-4:0}=
#→ ${"ABCDE":-3:0}=
#→ ${"ABCDE":-2:0}=
#→ ${"ABCDE":-1:0}=
#→ ${"ABCDE":0:0}=
#→ ${"ABCDE":1:0}=
#→ ${"ABCDE":2:0}=
#→ ${"ABCDE":3:0}=
#→ ${"ABCDE":4:0}=
長さをゼロにするとエラーにはなりませんが、なにも返って来ません
開始位置がゼロ及び正の整数、長さが負の整数の場合
#開始位置が0及び正の整数、長さが負の整数
str=ABCDE; for i in {0..4}; for j in {$(($i-5))..-1}; do echo '${"ABCDE":'$i':'$j'}='${str:$i:$j} ; done
#→ ${"ABCDE":0:-5}=
#→ ${"ABCDE":0:-4}=A
#→ ${"ABCDE":0:-3}=AB
#→ ${"ABCDE":0:-2}=ABC
#→ ${"ABCDE":0:-1}=ABCD
#→ ${"ABCDE":1:-4}=
#→ ${"ABCDE":1:-3}=B
#→ ${"ABCDE":1:-2}=BC
#→ ${"ABCDE":1:-1}=BCD
#→ ${"ABCDE":2:-3}=
#→ ${"ABCDE":2:-2}=C
#→ ${"ABCDE":2:-1}=CD
#→ ${"ABCDE":3:-2}=
#→ ${"ABCDE":3:-1}=D
#→ ${"ABCDE":4:-1}=
長さがマイナスの場合は、長さではなく取り出す最後の位置を、末尾からのオフセットで指定します
結果として最後の文字は取り出すことができません
わかりにくいですね
開始位置が負の整数、長さが負の整数の場合
#開始位置が負の整数、長さが負の整数
str=ABCDE; for i in {-5..-1}; for j in {$(($i))..-1}; do echo '${"ABCDE":'$i':'$j'}='${str:$i:$j} ; done
#→ ${"ABCDE":-5:-5}=
#→ ${"ABCDE":-5:-4}=A
#→ ${"ABCDE":-5:-3}=AB
#→ ${"ABCDE":-5:-2}=ABC
#→ ${"ABCDE":-5:-1}=ABCD
#→ ${"ABCDE":-4:-4}=
#→ ${"ABCDE":-4:-3}=B
#→ ${"ABCDE":-4:-2}=BC
#→ ${"ABCDE":-4:-1}=BCD
#→ ${"ABCDE":-3:-3}=
#→ ${"ABCDE":-3:-2}=C
#→ ${"ABCDE":-3:-1}=CD
#→ ${"ABCDE":-2:-2}=
#→ ${"ABCDE":-2:-1}=D
#→ ${"ABCDE":-1:-1}=
このパターンもわかりにくいですが、
開始位置も長さ(終了位置)も同じマイナスでの指定なので
そこまで難解なわけでもないかな
まとめ
各項目のバリエーションと取りうる範囲として表にしました(が、解りにくいですね)
項目 | セット値 | 例1 | 例2 | 例3 | 例4 | 例5 |
---|---|---|---|---|---|---|
①文字列 | サンプル値 ="ABCDE" |
A | B | C | D | E |
②-1 開始位置 |
0及び正の整数 (オフセット) |
0 | 1 | 2 | 3 | 4 |
②-2 開始位置 |
負の整数 (末尾からの変位) |
-4 | -3 | -2 | -1 | 0 |
③-1 長さ |
0 (Nullを返却) |
Null | Null | Null | Null | Null |
③-2 長さ |
正の整数 (取り出す文字数) |
1〜5 | 1〜4 | 1〜3 | 1〜2 | 1 |
結果 | A〜ABCDE | B〜BCDE | C〜CDE | D〜DE | E | |
③-3 長さ |
負の整数 (末尾からの変位) |
-5〜-1 | -4〜-1 | -3〜-1 | -4〜-1 | -1 |
結果 | -5はNull -4からはA〜ABCD |
-4はNull -3からはB〜BCD |
-3はNull -2からはC〜CD |
-2はNull -1はD |
Null | |
③-4 長さ |
省略 (最長文字数) |
5 | 4 | 3 | 2 | 1 |
結果 | ABCDE | BCDE | CDE | DE | E |
※「長さ」は、負の整数の場合、末尾からの変位となり、その位置の直前までしか取り出せません。そのため正の整数と負の整数で完全な互換性はありません(最後の文字が取り出せません)
※「長さ」は、ゼロだとNullがリターンされ、省略すると末尾までの文字列がリターンされます