|Home|私のLinux活用記録-Home-|

私のLinux活用記録

-Page21-

 

[bash シェルスクリプト(初歩の実践編)]

作成:2005年02月20日
修正:2005年08月28日

900 以上もある「英訳パーリ語経典テキスト」の HTML ファイルに対して、当サイトの体裁への変更、strict.dtd への書き換え、経典以外へのリンク削除等の変更を加えるのは、相当骨の折れる作業です。
前回は全てハンドで書き換えましたが、さすがに今回はハンドで書き換えるのはためらいました。そこで今回は、bash シェルスクリプトによる書き換えに挑戦しました。完全自動というわけではありませんが、かなり満足な書き換えができたので、以下にその結果をまとめました。

[参考] bash シェルスクリプトについては、以下も参考にしてください。
kh17-02[bash シェルスクリプトの基礎知識]

[参考ホームページ]
■ コマンド
http://www.net-sintech.jp/linux/
http://itpro.nikkeibp.co.jp/members/LIN/LIN_CONTENTS/20020531/1/
■ テキスト処理
http://cyberam.dip.jp/linux_command/command/text_proc.html
http://infosys.gsid.nagoya-u.ac.jp/~ohna/perl_lesson/index.html
■ シェルスクリプト
http://cyberam.dip.jp/linux_command/shellscript.html
■ 正規表現
http://www.sixnine.net/index.html
http://www.kt.rim.or.jp/~kbk/regex/regex.html

kh21-01.01 元ファイルの内容
kh21-01.02 編集後のファイルの内容
kh21-01.03 編集に用いた bash シェルスクリプト
kh21-01.04 スクリプト処理内容の説明
kh21-01.05 コマンドの用法
kh21-01.06 正規表現、その他

戻る

元ファイルの内容

黒字部分
削除して、別の内容に変更する部分
緑字部分
文字列を抽出して書き加えるか、原文のまま維持する部分
赤字部分
strict.dtd 対応のために書き直す部分
青字部分
表示形式変更およびリンク削除のために書き換える部分
line -------------------------- original file --------------------------
   :
001:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   :    "http://www.w3.org/TR/html4/loose.dtd">
002:<HTML>
003:<HEAD>
004:<TITLE>SN I.1: Ogha-tarana Sutta</TITLE>
005:</HEAD>
006:<BODY bgcolor="#FFFFFF">
007:<SMALL>
008:<A HREF="../../../help.html" name="top"><B>Help</B></a>
009:<A HREF="../../../index.html"><B>Home</B></a>
010:&raquo; <A HREF="../../index.html">Tipitaka</a>
011:&raquo; <A HREF="../index.html">Sutta Pitaka</a>
012:&raquo; <A HREF="index.html">Samyutta Nikaya</a>
013:&raquo; <A HREF="index.html#sn01-001">Context of this sutta</a>
014:</SMALL>
015:<center>
016:<h3>Samyutta Nikaya I.1</h3>
017:<h1>Ogha-tarana Sutta</h1>
018:<h1>Crossing over the Flood</h1>
019:.....
020:</center>
021:<hr>
022:.....
023:.....
024:<blockquote>
025:.....
026:</blockquote>
027:.....
028:<center>
029:.....
030:</center>
031:.....
032:<h3 align="center">.....</h3>
033:.....
034:<hr width="50%">
035:.....
036:<a href="URL(Type1)">(Type1)</a>
037:.....
038:<a href="URL(Type2)">(Type2)</a>
039:.....
040:.....
041:<hr>
042:<small>
043:Revised: <!--_REV_DATE_START_-->Sunday 2005.01.02→
   :→<!--_REV_DATE_END_--><br>
044:</small>
045:<address>
046:<a href="http://accesstoinsight.org/canon/sutta/samyutta/→
   :→sn01-001.html">http://accesstoinsight.org/canon/sutta/samyutta/→
   :→sn01-001.html</a></address>
047:</body>
048:</html>
   :
end  -------------------------- original file --------------------------

戻る

編集後のファイルの内容

黒字部分
削除して、別の内容に変更した部分
元01-15 → 編01-29
元47-48 → 編65-77
緑字部分
文字列を抽出して書き加えたか、原文のまま維持した部分
元04  → 編08
元10-13 → 編25-27
元16-18 → 編30-32
その他は原文を維持
赤字部分
strict.dtd 対応のために書き直した部分
元20  → 編34
元24-26 → 編38-40
元28-30 → 編42-44
元32  → 編46-48
元34  → 編50-52
青字部分
表示形式変更およびリンク削除のために書き換えた部分
元18 → 編32
元38 → 編56
元46 → 編64
line -------------------------- rewrited file --------------------------
   :
001:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
002:    "http://www.w3.org/TR/html4/strict.dtd">
003:<html>
004:<head>
005:    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
006:    <meta http-equiv="Content-Style-Type" content="text/css">
007:    <link rel="stylesheet" href="style_canon.css" type="text/css">
008:    <title>SN I.1: Ogha-tarana Sutta</title>
009:    <script type="text/javascript">
010:    <!--
011:    function new_window(url) {
012:    window.open(url,'','scrollbars=1,toolbar=1,menubar=1,location=1').focus();
013:    }
014:    // -->>
015:    </script>
016:</head>
017:<body>
018:<p><a name="homep"></a>
019:<table border="0" width="720px" style="color: #000000; background-color: #ffffff">→
   :→<!-- main-box -->
020:<tr><td>
021:<div class="main-doc"><!-- main-doc -->
022: <br>
023:<small>
024:<b><a href="http://panna.zive.net/bukkyo/bukkyo_bk03.html" name="top">→
   :→Buddhism-page3-</a></b>
025:&raquo; <A HREF="../index.html">Sutta Pitaka</a>
026:&raquo; <A HREF="index.html">Samyutta Nikaya</a>
027:&raquo; <A HREF="index.html#sn01-001">Context of this sutta</a>
028:</small>
029:<div class="center"><!-- <center> -->
030:<h3>Samyutta Nikaya I.1</h3>
031:<h1>Ogha-tarana Sutta</h1>
032:<h2>Crossing over the Flood</h2>
033:.....
034:</div><!-- </center> -->
035:<hr>
036:.....
037:.....
038:<div class="margin40p"><!-- <blockquote> -->
039:.....
040:</div><!-- </blockquote> -->
041:.....
042:<div class="center"><!-- <center> -->
043:.....
044:</div><!-- </center> -->
045:.....
046:<div class="center">
047:<h3>.....</h3>
048:</div>
049:.....
050:<div class="margin_lr25">→
   :→<!-- <hr width="50%"> -->
051:<hr>
052:</div>
053:.....
054:<a href="URL(Type1)">(Type1)</a>
055:.....
056:<span class="u-line">(Type2)</span>
057:.....
058:.....
059:<hr>
060:<small>
061:Revised: <!--_REV_DATE_START_-->Sunday 2005.01.02→
   :→<!--_REV_DATE_END_--><br>
062:</small>
063:<address>
064:<a href="#jp_valid" onCLick="new_windw('http://accesstoinsight.org/→
   :→canon/sutta/samyutta/sn01-001.html')">http://accesstoinsight.org/→
   :→canon/sutta/samyutta/sn01-001.html</a></address>
065:</div><!-- end of main-doc -->
066:&nbsp;
067:</td></tr>
068:</table><!-- end of main-box -->
069:<table border="0" width="720px">
070:<tr><td align="center">
071:<a name="jp_valid"></a>
072:&nbsp;
073:<br><a href="#jp_valid" onclick="new_window('http://validator.w3.org/→
   :→check/referer')"><img src="valid-html401.gif" alt="Valid HTML 4.01!" →
   :→width="88px" height="31px"></a>&nbsp;<a href="#jp_valid" onClick=→
   :→"new_window('http://jigsaw.w3.org/css-validator/')"><img src="vcss.gif" →
   :→alt="Valid CSS!" width="88px" height="31px"></a>
074:</td></tr>
075:</table>
076:</body>
077:</html>
   :
end  -------------------------- rewrited file --------------------------

戻る

編集に用いた bash シェルスクリプト

line -------------------------- bash shell script --------------------------
   :
100:#!/bin/sh
101:
102:##############################################
103:# rewrite sutta HTML from original to my form
104:# Ver 1.8 / 2005.02.16 / by S.Tamura
105:##############################################
106:
107:# set directory name where files are
108:DIR="canon/sutta/samyutta"
109:
110:# declare variable as integer
111:declare -i LINE
112:
113:# make log file
114:echo "" > chk_log
115:
116:# make file list
117:ls $DIR > list
118:grep "\.html" list > list_b
119:echo "endend" >> list_b
120:cat list_b > list
121:
122:# initialize while loop
123:head -n 1 list > file
124:sed -e "1,1d" list > list_b
125:cat list_b > list
126:FILE=`cat file`
127:echo "read " $FILE
128:
129:# while loop
130:while [ $FILE != "endend" ]
131:  do
132:
133:  # get title name and make <title>TITLE_NAME</tille>
134:  grep -E "<title>|<TITLE>" $DIR/$FILE > title
135:  sed -e "s/<TITLE>/<title>/" title > title_b
136:  sed -e "s/<\/TITLE>/<\/title>/" title_b > title
137:  TITLE=`cat title`
138:  echo ${TITLE#*<title>} > title
139:  TITLE=`cat title`
140:  echo ${TITLE%%</title>*} > title
141:  TITLE=`cat title`
142:  echo "    <title>"$TITLE"</title>" > title
143:
144:  # get lines contain "&raquo;"
145:  grep -E "^[[:blank:]]*&raquo;" $DIR/$FILE > raquo
146:
147:  # replace "<A HREF=" & "</A>"
148:  sed -e "s/<[aA] \(HREF\|href\)=\"/<a href=\"/g" $DIR/$FILE > file
149:  sed -e "s/<\/A>/<\/a>/g" file > file_b
150:  cat file_b > file
151:
152:  # get line number contain "<[hH][123]" and cut lines to $LINE-1
153:  grep -n -E "<[hH][123]" file > h123
154:  head -n 1 h123 > h123_b
155:  cut -f 1 -d ":" h123_b > line
156:  LINE=`cat line`
157:  LINE=$LINE-1
158:  echo "1,"$LINE"d" > script
159:  sed -f script file > file_b
160:  cat file_b > file
161:
162:  # output "<h3>...</h3>"
163:  cat _ins2 > ins2
164:  grep -n -E "</[hH][123]>" file > h123
165:  head -n 1 h123 > h123_b
166:  cut -f 1 -d ":" h123_b > line
167:  LINE=`cat line`
168:  head -n $LINE file > h123
169:  grep "</[hH]3>" h123 > h3
170:  H3=`cat h3`
171:  if [ "$H3" != "" ]
172:    then
173:    cat h123 >> ins2
174:    echo "1,"$LINE"d" > script
175:    sed -f script file > file_b
176:    cat file_b > file
177:  fi
178:
179:  # output "<h1>...</h1>"
180:  grep -n -E "</[hH][12]>" file > h12
181:  head -n 1 h12 > h12_b
182:  cut -f 1 -d ":" h12_b > line
183:  LINE=`cat line`
184:  head -n $LINE file > h12
185:  cat h12 >> ins2
186:  echo "1,"$LINE"d" > script
187:  sed -f script file > file_b
188:  cat file_b > file
189:
190:  # replace "<h2>...</h2>"
191:  grep -n -E "</[hH][12]>" file > h12
192:  head -n 1 h12 > h12_b
193:  cut -f 1 -d ":" h12_b > line
194:  LINE=`cat line`
195:  head -n $LINE file > h12
196:  if [ "$H3" != "" ]
197:    then
198:    sed "s/<[hH]1/<h2/" h12 > h12_b
199:    sed "s/<\/[hH]1>/<\/h2>/" h12_b > h12
200:  fi
201:  cat h12 >> ins2
202:  echo "1,"$LINE"d" > script
203:  sed -f script file > file_b
204:  cat file_b > file
205:
206:  # get last line number contain "<a href=\"http://(www\.)?access"
207:  # get last line contain "<a href=\"http://(www\.)?access"
208:  # get lines from top to $LINE-1
209:  grep -n -E "<a href=\"http://(www\.)?access" file > hrefn
210:  tail -n 1 hrefn > hrefn_b
211:  cut -f 1 -d ":" hrefn_b > line
212:  LINE=`cat line`
213:  LINE=$LINE-1
214:  grep -E "<a href=\"http://(www\.)?access" file > href
215:  tail -n 1 href > href_b
216:  head -n $LINE file > file_b
217:  cat href_b > href
218:  cat file_b > file
219:
220:  # replace "<a href=\"http://....html\">http://" in last line
221:  sed -e "s/<a href=\"http:\/\//<a href=\"\#jp_valid\" onClick=\"new_window→
   :  →(\'http:\/\//" href > href_b
222:  sed -e "s/html\">http:\/\//html\')\">http:\/\//" href_b > href
223:
224:  # check " align=" & " width="
225:  grep -E "\balign[[:blank:]]*=|\bALIGN[[:blank:]]*=" file > check
226:  head -n 1 check > check_b
227:  CHECK=`cat check_b`
228:  if [ "$CHECK" != "" ]
229:    then
230:    echo $FILE >> chk_log
231:    echo "** align ** : yes" >> chk_log
232:  fi
233:  grep -E "\bwidth[[:blank:]]*=|\bWIDTH[[:blank:]]*=" file > check
234:  head -n 1 check > check_b
235:  CHECK=`cat check_b`
236:  if [ "$CHECK" != "" ]
237:    then
238:    echo $FILE >> chk_log
239:    echo "** width ** : yes" >> chk_log
240:    echo "" >> chk_log
241:  fi
242:
243:  # replace "&dagger;"
244:  # replace "<center>", "</center>", "<blockquote>", "</blockquote>"
245:  # replace "<img border="0" src="*/scrollup.gif"
246:  sed -e "s/\&dagger;/\&raquo;/g" file > file_b
247:  sed -e "s/<center>\|<CENTER>/<div style=\"text-align: center\">→
   :  →<!-- <center> -->/g" file_b > file
248:  sed -e "s/<\/center>\|<\/CENTER>/<\/div><!-- <\/center> -->/g" file > file_b
249:  sed -e "s/<blockquote>\|<BLOCKQUOTE>/<p><div style=\"margin-left: 40px\">→
   :  →<!-- <blockquote> -->/g" file_b > file
250:  sed -e "s/<\/blockquote>\|<\/BLOCKQUOTE>/<\/div><!-- <\/blockquote> -->/g" →
   :  →file > file_b
251:  sed -e "s/<\(img\|IMG\) \(border\|BORDER\)=\"0\" \(src\|SRC\)=\"\(\.\.\/\)*→
   :  →icon\/scrollup\.gif/<img src=\"scrollup\.gif/g" file_b > file
252:
253:  # replace "<a href=\"(../)*URL(Type2)\">"
254:  perl -pe 's/<a href="(\.\.\/)+lib\/.*?">/<span class="u-line">/g' file > file_b
255:  perl -pe 's/<a href="(\.\.\/)+index-sutta\.html.*?">/<span class=→
   :  "u-line">/g' file_b > file
256:  .................
257:  cat file_b > file
258:
259:  # replace "<span class=\"u-line\">...</a>"
260:  grep -E "<span class=\"u-line\">" file > spans
261:  echo "endend" >> spans
262:  head -n 1 spans > span
263:  SPAN=`cat span`
264:  sed -e "1,1d" spans > spans_b
265:  cat spans_b > spans
266:
267:  while [ "$SPAN" != "endend" ]
268:    do
269:    grep -E "<span class=\"u-line\">" span > flag
270:    FLAG=`cat flag`
271:
272:    while [ "$FLAG" != "" ]
273:      do
274:      echo ${SPAN#*<span class=\"u-line\">} > span
275:      SPAN=`cat span`
276:      echo ${SPAN%%</a>*} > link
277:      sed -e 's/\//\\\//g' link > link_b
278:      sed -e 's/\&/\\\&/g' link_b > link
279:      LINK=`cat link`
280:      echo "s/<span class=\"u-line\">"$LINK"<\/a>/<span class=\"u-line\">"→
   :      →$LINK"<\/span>/" > script
281:      sed -f script file > file_b
282:      cat file_b > file
283:
284:      grep -E "<span class=\"u-line\">" span > flag
285:      FLAG=`cat flag`
286:      done
287:
288:    head -n 1 spans > span
289:    SPAN=`cat span`
290:    sed -e "1,1d" spans > spans_b
291:    cat spans_b > spans
292:    done
293:
294:  # marge each file & output $FILE
295:  cat _top > top
296:  cat title >> top
297:  cat _ins1 >> top
298:  cat raquo >> top
299:  cat ins2 >> top
300:  cat file >> top
301:  cat href >> top
302:  cat _bottom >> top
303:  cat top > new/$FILE
304:  echo "write" $FILE
305:
306:  # set condition for while loop
307:  head -n 1 list > file
308:  sed -e "1,1d" list > list_b
309:  cat list_b > list
310:  FILE=`cat file`
311:
312:  echo "read " $FILE
313:  done
   :
end  -------------------------- bash shell script --------------------------

戻る

スクリプト処理内容の説明

基本的な用法しか使っていないので、随分冗長なスクリプトだとは思いますが、初歩のスクリプトですので御容赦ください。しかし確実に動きます。
100
bash シェルスクリプトの宣言
108
対象ファイルが配置されたディレクトリの相対パスを変数 DIR にセット
111
変数 LINE を整数として宣言
114
後述する "align" や "center" 属性を使用しているファイル名を記録するためのログファイルの初期化
117-120
HTMLファイル名リストを作成し、最終行に終了文字列 "endend" を追記
123-127
HTMLファイル名リストの最初の行からファイル名を変数 FILE の値にセットした後、ファイル名リストの最初の行を削除
130-313
トップレベルの while ループ
終了条件は、FILE の値が "endend" になったとき
各 HTMLファイルに対して、書き換えを実行する。
ループ条件の更新は、307-310(123-127 と同じ)
134
HTMLファイルから "<title>" または "<TITLE>" を検索し、マッチした行をファイル title に書き出す。
135-136
ファイル title 中の "<TITLE>", "</TITLE>" タグを小文字に置換
137-142
"<title>" と "</title>" に囲まれた文字列を抽出し、ファイル title に "    <title>抽出文字列</tilte>" を書き出す。
145
HTMLファイルから "&raquo;" で始まる行を検索し、マッチした行をファイル raquo に書き出す。
148-150
HTMLファイル中の "<A HREF=\"" および "</A>" を小文字に変換
153-160
HTMLファイルに出現する最初の "<h1>" or "<h2>" or "<h3>"(大文字も含む) を検索し、その行番号を取得する。取得した行番号のひとつ手前までの行を HTMLファイルから削除し、残りを以降の処理対象ファイル(HTMLファイル) とする。
163-177
HTMLファイルに出現する最初の "</h1>" or "</h2>" or "</h3>"(大文字も含む) を検索し、その行番号を取得する。HTMLファイルの 1行目から取得した行番号までをファイル h123 に書き出し、それが "</h3>" を含む場合は、h123 を挿入用ファイル ins2(_ins2 のコピー) にマージする。併せて、HTMLファイルから、取得した行番号までを削除する。
180-188
HTMLファイルに出現する最初の "</h1>" or "</h2>"(大文字も含む) を検索し、その行番号を取得する。HTMLファイルの 1行目から取得した行番号までをファイル h12 に書き出し、挿入用ファイル ins2 にマージする。併せて、HTMLファイルから、取得した行番号までを削除する。
191-204
HTMLファイルに出現する最初の "</h1>" or "</h2>"(大文字も含む) を検索し、その行番号を取得する。HTMLファイルの 1行目から取得した行番号までをファイル h12 に書き出し、先の 163-177 で "</h3>" が出現している場合は、ファイル h12 中の "<h1>" and "</h1>"(大文字も含む) を "<h3>" and "</h3>" に書き換え、挿入用ファイル ins2 にマージする。併せて、HTMLファイルから、取得した行番号までを削除する。
209-218
HTMLファイルに出現する最後の "<a href=\"http://(www\.)?access" を検索し、その行番号を取得する。最後に出現した行をファイル href に書き出す。併せて、取得した行の手前までを HTMLファイルとして取り出す。
221-222
ファイル href 中の "<a href=\"http://.....html\">http://" を
"<a href=\"#jp_valid\" onClick=\"new_window(\'http://.....html\')\">http://" に書き換える。
225-241
HTMLファイル中に、" align=" or " center=" があれば、元の HTMLファイル名と存在の記録をファイル chk_log に、書き加える。
[注]
"align" や "center" 属性は、いろいろなタグに使用されており、また出現頻度が低いので、スクリプトによる書き換えはあきらめました。ログファイルを参照して、対象ファイルをハンドで書き換えるようにしました。
246-257
HTMLファイル中の "&dagger;" を "&raquo;" に書き換える。また、loose.dtd のタグ "<center>", "</center>", "<blockquote>", "</blockquote>"(大文字も含む) を strict.dtd 対応に書き換える。さらに、"<img border=\"0\" src=\"*/scrollup.gif"(大文字も含む) を "<img src=\"scrollup.gif" に書き換える。
254-257
HTMLファイル中の "<a href=\"(../)*URL(Type2)\">" を "<span class=\"u-line\">" に書き換える。
260-261
HTMLファイルから "<span class=\"u-line\">" を検索して、該当行をファイル spans に書き出し、最終行に終了文字列 "endend" を追記する。
[注] "u-line" は、文字列にアンダーラインを付けるために、スタイルシートで定義されたクラス名
262-265
ファイル spans の 1行目をファイル span に読み出すとともに変数 SPAN の値としてセットする。次いで、ファイル spans の 1行目を削除する。
267-292
第2レベルの while ループ
終了条件は、SPAN の値が "endend" になったとき
HTMLファイルに対して、書き換えを実行する。
ループ条件の更新は、288-291(262-265 と同じ)
269-270
ファイル span 中の "<span class=\"u-line\">" を検索し、マッチした行の文字列を変数 FLAG の値としてセット
272-286
第3レベルの while ループ
終了条件は、FLAG の値が ""(空文字列) になったとき
HTMLファイルに対して、書き換えを実行する。
ループ条件の更新は、284-285(269-270 と同じ)
274-279
変数 SPAN の値(文字列) の先頭から、"<span class=\"u-line\"> に最短でマッチする文字列を削除し、あらたに変数 SPAN の値としてセットする。次いで、変数 SPAN の値(文字列) の末尾から、"</a>" に最長でマッチする文字列を削除し、ファイル link に書き出す。ファイル link 中の "/" と "&" に対し "\" を付けてエスケープし、得られた文字列を変数 LINK の値にセットする。
280-282
HTMLファイル中の、"<span class=\"u-line\">"$LINK"</a>" を "<span →
→class=\"u-line\">"$LINK"</span>" に書き換える。
295-304
前もって作成したファイル _top に対して、ファイル title, _ins1, raquo, ins2, file(編集した HTMLファイル本体), href, _bottom を順番にマージし、最後にディレクトリ new に元ファイル名で書き出す。
[参考] マージした各ファイルの内容と編集後 HTMLファイルの各行の対応
_top   :編01-07
title  :編08
_ins1  :編09-24
raquo  :編25-27
ins2   :編28-32
file   :編33-63
href   :編64
_bottom:編65-77

戻る

コマンドの用法

今回の事例は特殊なケースかもしれませんが、用いたコマンドとその用法、正規表現の使い方はなにがしかの参考になると思い、整理してみました。

用いたコマンドは、ls, echo, cat, grep, cut, head, tail, sed, perl です。sed と perl はスクリプトを引数とし、コマンドとは呼ばないようですが、シェルスクリプトの中では、コマンドと同じように扱えます。

ls
説明するほどのこともないので こちらを参照 してください。
echo
文字列や変数の値を出力します。
 
$ echo "文字列"
"文字列" を出力します。

$ echo $VAR
変数 VAR の値をを出力します。
 
$ echo "文字列"$VAR
"文字列" に続けて変数 VAR の値を出力します。
cat
ファイルの内容を出力します。
 
$ cat file
ファイル file の内容をモニターに出力します。
 
$ cat file > file1
ファイル file の内容を ファイル file1 に上書き出力します。
 
$ cat file >> file1
ファイル file の内容を ファイル file1 に追加出力します。

[注] ">" および ">>" は、全ての出力に対して有効です。
grep
ファイル file 中の検索文字列(正規表現) を検索し、マッチした行を出力します。
grep -E "検索文字列(正規表現)" file
-E オプションは、拡張正規表現が使えます。

マッチした行の行頭に行番号を挿入して出力するには
grep -n -E "検索文字列(正規表現)" file
この場合、行頭に "行番号:" が挿入されます。

cut
ファイル中の各行について、指定した文字数の場所、またはフィールド数の場所から文字列を取り出して出力します。
詳しい用法は、こちらを参照 してください。

ここでは、行番号を取り出すために
cut -f 1 -d ":" file
を用いています。区切り文字を ":" として、1番目のフィールドの文字列を出力します。

head
ファイル file の先頭行から指定行数(N) を出力します。
head -n N file
tail
ファイル file の最終行から指定行数(N) を出力します。
tail -n N file
sed
ファイル中の文字列の置換、および指定した行番号の行削除を行い出力します。
 
$ sed -e "s/被置換文字列(正規表現)/置換文字列/" file
ファイル file の各行について、被置換文字列(正規表現) に最初にマッチした文字列だけを置換文字列に置換して出力します。
[注]
被置換文字列(正規表現) に ".*" を用いた場合、最長マッチの文字列が置換されます(最短マッチの文字列を置換するには perl 使用)。
 
$ sed -e "s/被置換文字列(正規表現)/置換文字列/g" file
ファイル file の各行について、被置換文字列(正規表現) にマッチした全ての文字列を置換文字列に置換して出力します。
[注]
被置換文字列(正規表現) に ".*" を用いた場合、最長マッチの文字列が置換されます(最短マッチの文字列を置換するには perl 使用)。
 
$ sed -e "M,Nd" file
ファイル file の M行目から N行目までを削除して出力します。
 
$ sed -f script file
処理スクリプトを記述したファイル script を読み込んで行う処理
スクリプト中に、変数値などを用いたい場合、sed -e "スクリプト" が使えません。このような場合、変数値を埋め込んだスクリプトをファイル script に書き込み、
sed -f script file
で、ファイル file に対する処理を行います(例:158-159, 186-187, 202-203, 280-281)

オプション -e は、次に続くスクリプトを読み取り処理する。
オプション -f は、次に続くファイルからスクリプトを読み取り処理する。

perl
sed では処理できない最短マッチの文字列置換に使用しました。
 
$ perl -pe "s/被置換文字列(正規表現)/置換文字列/" file
ファイル file の各行について、被置換文字列(正規表現) に最初にマッチした文字列だけを置換文字列に置換して出力します。
[注]
被置換文字列(正規表現) に ".*?" を用いた場合、最短マッチの文字列が置換される。
 
$ perl -pe "s/被置換文字列(正規表現)/置換文字列/g" file
ファイル file の各行について、被置換文字列(正規表現) にマッチした全ての文字列を置換文字列に置換して出力します。
[注]
被置換文字列(正規表現) に ".*?" を用いた場合、最短マッチの文字列が置換される(例:254-255)。

オプション -e は、次に続くスクリプトを読み取り処理する(sed と同じ)。
オプション -p は、ファイル file から処理対象データを読み取り、処理した後処理結果を出力する。

戻る

正規表現、その他

■ メタキャラクタとエスケープ文字("\")

正規表現を用いることができる grep, sed, perl では、各々正規表現に使われるメタキャラクタ(正規表現における特別な意味をもった文字) やエスケープ文字(通常文字の前に付けて特別な意味をもたせたり、メタキャラクタの前に付けてメタキャラクタを通常文字として扱う) の使われ方が異ります。これらについては、正規表現メモ によく整理されています。正規表現をこれから使おうという方は是非参照してみてください。

■ クォートの使いかた(bash の場合)

シングルクォート(『'』)
シングルクォートで文字を囲むと、クォート内部のそれぞれの文字は文字としての値を保持します。シングルクォートの間にシングルクォートを置くことはできません。シングルクォートの前にバックスラッシュ("\") を付けても同じです。
シングルクォートの中では、ダブルクォートがそのまま使えます。
ダブルクォート(『"』)
ダブルクォートで文字を囲むとクォート内部の全ての文字は文字としての値を保持します。ただし、 "$", "`", "\" は例外です。"$" と "`" はダブルクォートの内部でも特殊な意味を持ちます。前にバックスラッシュ("\") を付ければ、ダブルクォート文字をダブルクォートの内部でエスケープできます。

何だか頭の中がグルグル回るようですが、ダブルクォートの方が汎用性が高いようなので、私の場合はダブルクォートを優先的に使用し、ダブルクォートでうまくいかないときだけシングルクォートを使うようにしています。

sed や perl の引数としてのスクリプトにおいても、基本は bash と同じですが、微妙に異なる部分があるので、作用を確認しながら使用すべきでしょう。

■ sed で "/" を "\/" に置換するには

sed が引用するスクリプト中に通常文字として使用する "/" や "&" が含まれていると、正しく処理が行われません。事前に "\/" や "\&" に置換しておく必要があります。

$ sed -e 's/\//\\\//' とします

$ sed -e "s/\//\\\//" ではエラーが出ます。何故?.. 試しに

$ sed -e "s/\//X/" とすると、

"/" は正しく "X" に置き換わります。ということは、"\\\/" が "\/" を表現していない、つまり 『"』で囲まれたスクリプトでは、"\" は "\" をエスケープできないということになります。一方、『'』で囲まれたスクリプトでは、"\" は "\" をエスケープできるということのようです。

同様に、"&" を "\&" に置換する場合も

$ sed -e 's/\&/\\\&/' とします

■ 最長マッチと最短マッチ

正規表現では、".*" は非常に便利な表現です。これは、空文字または任意の長さの文字列を表現しています。例えば、"abc.*xyz" は "abc" で始まり "xyz" で終わる文字列です。では、処理対象の文字列が "abc-xyz-def-xyz" だとしたら、"abc.*xyz" は、"abc-xyz" にマッチするのか "abc-xyz-def-xyz" にマッチするのかというと、"abc-xyz-def-xyz" にマッチします。
grep や sed の正規表現では、".*" は最長マッチすることになっていて、最短マッチさせる表現方法がありません。しかしありがたいことに、最短マッチする表現は perl の正規表現に準備されています。perl では ".*?" を使えば最短マッチします。"abc.*?xyz" とすれば "abc-xyz" にマッチします。文字列置換の時に便利な用法です。

■ 文字列変数の処理

ファイル file が、"xxxx<b>文字列1</b>yyyy<b>文字列2</b>zzzz" という 1行で構成されているとします。ここで "文字列1" と "文字列2" の取り出し方を説明します。

まず処理対象文字列を、変数 STRING の値にセットします。
STRING=`cat file`

${STRING#*<b>}
"文字列1</b>yyyy<b>文字列2</b>zzzz" を出力します。すなわち、行頭から "<b>" に最短マッチした部分を取り除きます。

${STRING##*<b>}
"文字列2</b>zzzz" を出力します。すなわち、行頭から "<b>" に最長マッチした部分を取り除きます(何故か、STRING が 255文字を越えるとエラーになるので注意)。

${STRING%</b>*}
"xxxx<b>文字列1</b>yyyy<b>文字列2" を出力します。すなわち、行末から "</b>" に最短マッチした部分を取り除きます(何故か、STRING が 255文字を越えるとエラーになるので注意)。

${STRING%%</b>*}
"xxxx<b>文字列1" を出力します。すなわち、行末から "</b>" に最長マッチした部分を取り除きます。

これらを組み合わせて、

STRING=`cat file`
STRING=${STRING#*<b>}
echo ${STRING%%</b>*}
とすれば、"文字列1" が出力されます。

STRING=`cat file`
STRING=${STRING##*<b>}
echo ${STRING%</b>*}
とすれば、"文字列2" が出力されます。

[注]
ここで用いている "*" は、正規表現の "*" ではありません。いわゆるワイルドカードのような意味です。

戻る

counter1counter2counter3counter4counter5counter6

|Home|
 
Valid XHTML 1.1 Valid CSS!