- ベストアンサー
行の中の文字列の取出し方
- 行内の特定の文字列を抜き出す方法や、複数行から特定の行の特定の部分を抜き出す関数やシェルスクリプトについて教えてください。
- FreeBSDの環境でbashを使用しています。特定の行の中の特定の部分や複数行から特定の行の特定の部分を取り出す方法を教えてください。
- 行の中の文字列を取り出す方法や特定の行の特定の部分を取り出す関数やシェルスクリプトについて知りたいです。環境はFreeBSDでbashを使用しています。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
遅くなって申し訳ありません。 ANo.1です。 目的がわかりました。 「ネットワーク設定(1)」「ルーティング設定(2)」「リゾルバ設定(3,4)」から必要な項目を抽出したいわけですね。 先に前の解説をいたしますと 1.「~ s/[^ ]+ +([^ ]+).*/$1/;」 Perlというプログラム言語内で、文字列のパターンを操作する正規表現という手法を使っています。 「変数」部分はなんとなくお解かりになると思いますが 「=~」パターン結合演算子といいまして右辺側にて左辺変数に対しパターン操作を行うという演算子です。 「s/[^ ]+ +([^ ]+).*/$1/」肝心のこの部分ですが、説明のため以下のように分解します。 「s/パターン1/パターン2/」これは2項演算子という演算子の「置換」に分類されるものです。 パターン1の部分に一致した文字列をパターン2に置き換えるという機能です。 パターン1「[^ ]+ +([^ ]+).*」は文字列のパターンを正規表現という表現に置き換えたものです。 内部には3種のパターンを組み合わせています。(「(・・・)」についてはあとで解説) おのおの 「[^ ]+」空白を含まない文字列 「 +」空白列 「.*」0文字以上の文字列 実例から 「inet 192.168.11.3 netmask 0xffffff00 broadcast 192.168.11.255」の場合 「[^ ]+」→空白でない文字列「inet」に一致 「 +」→空白文字列「 」に一致 「([^ ]+)」→空白でない文字列(括弧はここでは無視してください)「192.168.11.3」に一致 「.*」→以降の文字列全て「 netmask 0xffffff00 broadcast 192.168.11.255」に一致 のようになります。 つまり「文字列1 空白 文字列2 空白と残りの文字列なら何でも」というパターンを表現しています。 これをパターン2に置き換えるのですが、このパターン2は「$1」となっております。 ここでパターン1の説明で無視した括弧部分に注目してください「([^ ]+)」。 この最初に括弧でくくられた部分が$1という変数に入ります。 これは文字列2のところについていますので 元の文字列全体を文字列2で置き換えているのです。 以上が1番目の解説です。 やっぱりよくわかりにくいですね。 正規表現はUNIXのツール類にはかなり昔からあって、SEDというUNIXでは古典的なエディタに出会ったときには使い道がよくわからずめげた経験があります。 grepコマンド(egrep)にもある程度備わっていて、なれると便利なのですが、何度も困りながら使い込んでゆかないとなかなか修得できないです。 2.問題4の処理部分 Perlというプログラム言語内で、「ハッシュ」とか「連想配列」と呼ばれているものを使っています。 変数を使ったデータベースのようなものだと思ってください。 「my %hS;」ハッシュ変数の宣言:$hS{文字列}のように文字列で変数を作る準備をします 「foreach(@A){ 処理 }」配列変数(0番から順番に番号の付いて並んだ変数と理解してください:「nameserver xxx.xxx.xxx.xxx」のデータが1行ずつ入っています)のデータ量分の回数、処理を行います。 「s/[^ ]+ +([^ ]+).*/$1/;」正規表現で2番目の文字列であるIPアドレス部を抽出 「exists($hS{$_})」抽出したIPアドレスですでにハッシュが作られているかどうかチェックします。(IF文は省略) まだ無ければ「$hS{$_} = 1;」カウント用に数値の1をセットします。 すでにあれば「$hS{$_}++;」カウントを+1します。 こうして処理していけば「%hS」にIPアドレスをキーワードとしたカウントデータが入るわけです。 あとはこのハッシュを展開表示してやればよいのです。 1から3はTRコマンドやCUTコマンドを組み合わせればプログラムを組まなくてもいけそうです(柔軟性がありませんが)。 (1)ifconfig |grep inet|tr -s ' ' ' '|cut -d' ' -f3 ネットワーク設定情報から inetを含む行を抽出して 複数の空白を1個ずつに加工し 空白を指標に三番目の要素(Linuxの場合先頭に空白があるため。質問のような形だと-f2とします)を抽出 (2)route |grep default|tr -s ' ' ' '|cut -d' ' -f2 (3)cat /etc/resolv.conf |grep domain|cut -d' ' -f2 4はさすがにスクリプトを組む必要があると思います。 #!/usr/bin/perl my $CMD = 'cat /etc/resolv.conf |grep nameserver|'; ## 実行するコマンド定義(結果を戻すため末尾に「|」を) open(IN01,$CMD); ## コマンドを実行して結果を配列変数に取得 my @A = <IN01>; close(IN01); ## 処理 my %hS; foreach(@A){ s/[^ ]+ +([^ ]+).*/$1/; if(exists($hS{$_})){ $hS{$_}++; }else{ $hS{$_} = 1; } } ## 表示 foreach my $k (sort keys %hS){ print '要素:'.$k." 出現回数:".$hS{$k}."\n"; これをファイルにして、コンソールから「perl ファイル名」で実行してください。 ながながとすいませんでした。
その他の回答 (1)
- ralf124c
- ベストアンサー率52% (232/446)
問題をまとめて見ますと (1) 1,2,3番の問題:スペースで区切られた文字列の2番目の要素を取り出す。 (2) 4番目の問題 :上記問題の延長で取り出す対象が複数の場合、取り出した文字列のダブりを省く 上記問題をSHELLスクリプトまたは関数(?コマンド??)で ここはPerlのカテゴリですので一応Perlでお答えしたいと思います。 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ #!/usr/local/bin/perl ## 問題1~3 ## データ準備 my $S1 = 'inet 192.168.11.3 netmask 0xffffff00 broadcast 192.168.11.255'; my $S2 = 'default 192.168.11.1 UGSc 17 5 en0'; my $S3 = 'domain odn.ne.jp'; ## 処理 $S1 =~ s/[^ ]+ +([^ ]+).*/$1/; $S2 =~ s/[^ ]+ +([^ ]+).*/$1/; $S3 =~ s/[^ ]+ +([^ ]+).*/$1/; ## 表示 print $S1."\n"; print $S2."\n"; print $S3."\n"; ## 問題4 ## データ準備 my @A = ( 'nameserver 192.168.11.1', 'nameserver 192.168.11.1', 'nameserver 192.168.11.2', 'nameserver 192.168.11.1', 'nameserver 192.168.11.1', 'nameserver 192.168.11.2', 'nameserver 192.168.11.1', 'nameserver 192.168.11.3', 'nameserver 192.168.11.1' ); ## 処理 my %hS; foreach(@A){ s/[^ ]+ +([^ ]+).*/$1/; if(exists($hS{$_})){ $hS{$_}++; }else{ $hS{$_} = 1; } } ## 表示 foreach my $k (sort keys %hS){ print '要素:'.$k." 出現回数:".$hS{$k}."\n"; } ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
お礼
大変ご丁寧な返答まことにありがとうございます。 ただ当方初心者でして、よく分かりません。 補足に書かせて頂きました箇所について、ご教授いただけましたら 幸いです。ありがとうございます。
補足
とても丁寧なご回答本当にありがとうございます。 詳しい方には理解出来ると思うのですが、当方初心者なので 分からない箇所が多く、しつこいようですが、ご教授願えましたら 幸いです。 my $S1 = 'inet 192.168.11.3 netmask 0xffffff00 broadcast 192.168.11.255'; ですが、右側の文字列は固定ではなく、次のコマンドで 拾ってきます。 >ifconfig |grep inet |grep -v 127 |grep inet6 これのレスが上の文字列になりますので、 変数に格納して・・・ としたいのですが、仕方が分かりません。 処理の所 $S1 =~ s/[^ ]+ +([^ ]+).*/$1/; なのですが、 右側の「~ s/[^ ]+ +([^ ]+).*/$1/;」はどういう意味なのでしょうか? 加えまして、 問題4の処理の所なのですが、 ********* ## 処理 my %hS; foreach(@A){ s/[^ ]+ +([^ ]+).*/$1/; if(exists($hS{$_})){ $hS{$_}++; }else{ $hS{$_} = 1; } } ## 表示 foreach my $k (sort keys %hS){ print '要素:'.$k." 出現回数:".$hS{$k}."?n"; } ********* すみません。解説いただけましたらありがたく存じます。 難しすぎて、恥ずかしい話ですが、さっぱり分かりません。 何度もしつこいようですが、周りにUnixやシェルを理解している 者が皆無なので、教えて頂けませんでしょうか。
お礼
大変詳しいご返答ありがとうございます。 s///演算子を使うのですね。正規表現もとても勉強になりました。 ハッシュの理解に手こずりましたが、 色々やっていたら何とか出来ました! ありがとうございました。