Movatterモバイル変換


[0]ホーム

URL:


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

2018.03.28
記事内に広告が含まれています。

環境変数IFSについて

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

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

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

区切り文字を設定

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

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

#!/bin/bashhead -n 5 /etc/passwd | while read USER PASS USERID GROUPID COMMENT HOMEDIR LOGINSHELLdo  echo "$USER $LOGINSHELL"done

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

$ sh ./IFS_1.shroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp: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/bashOLDIFS=$IFSIFS=:head -n 5 /etc/passwd | while read NAME PASS USERID GROUPID COMMENT HOMEDIR LOGINSHELLdo  echo "$NAME $LOGINSHELL"doneIFS=$OLDIFS

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

$ sh ./IFS_2.shroot /bin/bashbin /sbin/nologindaemon /sbin/nologinadm /sbin/nologinlp /sbin/nologin

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

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

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

$ cat list.txta b cd e fg i j

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

#!/bin/bashfor i in $(cat ./list.txt)do  echo $idone

2023.07.24 ファイルを読み込む場合は$(cat ./list.txt)よりも、$(< ./list.txt)の方が効率的であると、コメントにて教えていただきました。

catとリダイレクト(<)どちらの場合も、ファイルの内容を変数iに代入していますが、下記のような違いがあるため、一度だけファイルの内容を読み込む$(< ./list.txt)の方が効率的になります。

  • cat ファイルの内容を読み込むたびにcatを実行する
  • リダイレクト(<) ファイルの内容を一度だけ読み込む

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

$ sh ./IFS_3.shabcdefgij

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

#!/bin/bashOLDIFS=$IFSIFS=for i in $(cat ./list.txt)do  echo $idoneIFS=$OLDIFS

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

$ sh ./IFS_4.sha b cd e fg i j

IFSに改行を設定

bashで実行する場合

bashで実行する場合は「IFS=$'\n'」と指定することで、改行をIFSに指定することが出来ます。

このスクリプトでは、ファイルの内容が1行ごとに変数「i」に格納されていることがわかるように、変数「i」の内容を表示させる部分を「echo "echo $i"」としています。

#!/bin/bash OLDIFS=$IFSIFS=$'\n'for i in $(cat ./list.txt)do  echo "echo $i"done IFS=$OLDIFS

「bash」でスクリプトを実行すると、意図したとおりに1行ごとに変数に格納されて、表示されていることがわかります。

$ bash IFS_5.sh echo a b cecho d e fecho g i j

ちなみにUbuntuなどは「sh」が「dash」へのリンクとなっているので「sh」でスクリプトを実行すると、「IFS=$'\n'」が意図したように反映されません。

$ sh ./IFS_5.sh echo a b cd e fg i j

bash以外で実行する場合

bash以外でIFSに改行を設定する場合は、下記のように改行を入力して設定します。

IFS='(実際に改行)'
#!/bin/sh OLDIFS=$IFSIFS='' for i in $(cat ./list.txt)do  echo "echo $i"done IFS=$OLDIFS

ファイルの内容が1行ごと変数「i」に格納されて表示されています。

$ sh ./IFS_6.sh echo a b cecho d e fecho g i j

関連記事

シェルスクリプト

【シェルスクリプト】forやwhileによる繰り返しワンライナー

シェルスクリプト(bash)でforやwhileを使っての繰り返し処理を、ワンライナーで書く方法です。(自分用備忘録)forによる繰り返し基本はこんな感じです。for i in リスト; do コマンド; doneリスト部分にはブレーズ展開...
シェルスクリプト

【シェルスクリプト】月末かどうかを判定する方法

シェルスクリプト(bash)で月末の判定を行う方法です。月末判定シェルスクリプト今日が月末なのかを判定するシェルスクリプトです。date +%d --date '1 day'で次の日付を取得し、次の日が1日(01)であるかどうかで月末なのか...
シェルスクリプト

【シェルスクリプト】csvファイルを読み込んで処理するスクリプト

csvを読み込むシェルスクリプトテスト用として以下の区切り文字が「,」で、項目が3つあるcsvファイルを用意しました。$ cat test.csv 1,apple,1002,orange,803,nashi,1504,grape,3005,...
シェルスクリプト

【シェルスクリプト】ファイルやディレクトリの有無を確認する方法色々

シェルスクリプトでファイルやディレクトリが存在しているかどうかを確認する方法です。確認には「if」文を使っています。ファイルが存在する場合if文の演算子で「-e」を使うことでファイルが存在しているかどうかを確認することが出来ます。if ; ...
シェルスクリプト

【シェルスクリプト】ファイルの内容を比較して同じかどうかを調べる方法

「cmp」コマンドを使ってファイルの内容を比較して、同じかどうかで異なる処理を行うシェルスクリプトを紹介します。cmpコマンドについてcmpはファイルの内容を比較して、最初に差異があった箇所を表示してくれます。シェルスクリプトで「cmp」を...
シェルスクリプト

【bash】シェルスクリプトで関数を作成する方法 

bashのシェルスクリプトで関数を作成する方法です。関数とは関数とは簡単に説明すると「複数の処理をまとめたもの」です。関数を作成するメリット同じ処理を何度も行うのであれば、関数を作成してそれを呼び出すことで、何度も同じコード記述する必要がな...
スポンサーリンク

コメント

  1. けんじより:

    ファイルを読み込む時は、
    $(cat ./list.txt)
    より、
    $(< ./list.txt)
    の方が効率的です。

    • tamohikoより:

      けんじさん

      ファイルを読み込む際は、catで標準出力に表示させるよりも<で標準入力にリダイレクトさせるほうが効率的なのですね。勉強になりました、ありがとうございます。

  2. ぱぱおやじより:

    IFS_4.sh ですが IFS を空ではなく IFS=$’\n’ にしないとiにlist.txtの中身が全て入って見た目は同じでも意図と違う動作をしていませんか?

    • tamohikoより:

      ぱぱおやじさん

      1列づつ変数iに読み込むのであれば、IFS=$’\n’というように改行を指定しなくてはいけませんね。

      ご指摘ありがとうございます。

コメントをどうぞコメントをキャンセル

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

カテゴリー

最近の投稿

Jikage rising
2025.09.19
素晴らしいガイドですね!最小限インストールの手順がわかりやすくまとめられていて、初心者でも安心して進められます。おかげでスムーズにCentOS8をインストールできました。ありがとうございました!
CentOS8インストール(最小限インストール)
SpookyMilkLife
2025.08.18
非常に役立つ情報をありがとうございます!nmtuiの使い方が分かりやすく説明されていて、設定がスムーズにできました。今後もこのような記事を楽しみにしています!
NetworkManager 使用方法(nmtui編)
te
2024.05.22
こんにちはこちら記事、たいへんわかりやすかったです。ありがとうございます。
ssh-agentを使って公開鍵認証方式のsshパスワード入力を省略する方法
けんじ
2023.07.24
ファイルを読み込む時は、$(cat ./list.txt)より、$(< ./list.txt)の方が効率的です。
【シェルスクリプト】IFSで区切り文字(デリミタ)を変更する方法
たろう
2023.01.16
「pingで送信視するパケットサイズを指定した場合、指定したサイズ以外にもIPヘッダ(20バイト)とイーサネットフレーム(8バイト)が追加されて送信されます。」と記載がありますが、WireSharkで...
MTUの最適値を調べる方法
タイトルとURLをコピーしました

[8]ページ先頭

©2009-2025 Movatter.jp