LoginSignup
1
0

More than 1 year has passed since last update.

【じぶんメモ】シェルスクリプトで文字列の一部を取り出す

Last updated at Posted at 2022-03-11

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がリターンされ、省略すると末尾までの文字列がリターンされます

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0