server-memo.net

【シェルスクリプト】IFSで区切り文字(デリミタ)を変更する方法

   

環境変数IFSについて

環境変数「IFS」(Internal Filed Separator)には、bashの場合「スペース」「タブ」「改行」($' \t\n')といった値が初期設定されていて、これらが文字の区切りとして認識されています。

ファイル等を読み込んだりする場合に、読み込む文の区切り文字を変更したい場合は、「IFS」に区切り文字としたい値を設定することで、区切りとさせる文字を好きに設定することが出来ます。

例えばcsvファイルを読み込む場合等は「IFS」に「,」を設定するといったようにです。

区切り文字を設定

区切り文字の設定例として、「/etc/passwd」ファイルから「ユーザー名」と「ログインシェル」の情報を抜き出して表示させてみます。

この場合、「/etc/passwd」の各フィールド区切り文字は「:」となっているため、「IFS」を設定せずに下記のようなスクリプトで内容を抜き出そうとしてみます。

#/bin/bash
head -n 5 /etc/passwd | while read USER PASS USERID GROUPID COMMENT HOMEDIR LOGINSHELL
do
  echo "$USER $LOGINSHELL"
done

実際に実行してみると、初期設定では区切り文字に「:」は設定されていないため、一行まるまる「USER」変数に格納されてしまい、意図した結果が得られないことが確認できます。

$ sh ./IFS_1.sh
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

次に「:」をIFSに設定してみましょう。

最初に現在の「IFS」の設定を「OLDIFS=$IFS」でバックアップしてから「:」をIFSに設定し、「/etc/passwd」ファイルの各フィールドを、それぞれ「NAME」「PASS」「USERID」「GROUPID」「COMMENT」「HOMEDIR」「LOGINSHELL」といった変数に格納して、そこからユーザ名とログインシェルを表示させています。

最後にバックアップしてあった「IFS」の設定を元に戻しています。

#/bin/bash

OLDIFS=$IFS
IFS=:

head -n 5 /etc/passwd | while read NAME PASS USERID GROUPID COMMENT HOMEDIR LOGINSHELL
do
  echo "$NAME $LOGINSHELL"
done

IFS=$OLDIFS

今回は「:」が区切り文字として設定されているため、「:」で区切られた各フィールドがそれぞれの変数に格納されて、ユーザー名とログインシェルの部分のみ無事抜き出すことが出来ました。

$ sh ./IFS_2.sh
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin

空白・タブを含んだ文を扱いたい場合

空白やタブなどを区切り文字にしたくない場合は、IFSの値を空にすることで「スペース(空白)」「タブ」で区切ることなく読み込むことが出来ます。

例として空白を含んだ下記のファイルを使って挙動を確認してみます。

$ cat list.txt
a b c
d e f
g i j

まずは「IFS」を初期値のままで実行してみます。

#/bin/bash
for i in $(cat ./list.txt)
do
  echo $i
done

IFSの初期値は「スペース」「タブ」「改行」となっているため、スペースで区切られた文字が1文字ずつ変数iに格納されて、1文字ずつ表示されてしまします

$ sh ./IFS_3.sh
a
b
c
d
e
f
g
i
j

次にIFSの値を空に設定してみます。

#/bin/bash

OLDIFS=$IFS
IFS=

for i in $(cat ./list.txt)
do
  echo $i
done

IFS=$OLDIFS

区切り文字として「スペース」が設定されていないため、一列全部が変数iに格納されて表示されるようになりました。

$ sh ./IFS_4.sh
a b c
d e f
g i j

 - シェルスクリプト