perl5でunixの"wc"や"grep -c"みたいに1つのファイルの中からある文字列の個数を
カウントするスクリプトを作ろうとしています。

ファイルは256文字×10万行くらいのテキストで、
検索する文字列は15文字前後×40個(例えば「apple-000001」「lemon_orange」など)です。

どのようなスクリプトを組んだら効率よく各文字列をカウントできるのでしょうか?
それよりwcやgrep -cを40回行った方が早いのでしょうか?

このQ&Aに関連する最新のQ&A

A 回答 (3件)

最終的な速度については分かりませんが,Perl で効率良く実現しようというのであれば,配列(下の例では @pattern)に照合する文字列を入れておいて,ファイルから一行読むごとに,



foreach $pattern (@pattern) {
$count{$pattern} += /$pattern/g; #行の内容は $_ に入っていると仮定
}

とかしてやればよいのではないでしょうか。
一行にパターンが必ず一回しか現れないのであれば,2行目は,

$count{$pattern}++ if (/$pattern/);

とかすることも可能でしょう。

上記コードでは,パターン照合回数は grep を使ったときと同じですが,ファイルI/Oの回数は 1/パターン数 で済みます。が,パターン照合の速度そのものは grep のほうが速いでしょうから,最終的にどちらが速いかはやってみないと分かりません。

ちなみに,Perl のパターンマッチング処理は,一般に sed と同等或いはより高速だと言われているので,sed を使う意味はあまりないと思います。

この回答への補足

1000行25パターンのテストデータでやってみたところ
grep(25回)はperlの1.5倍処理時間がかかりました。
ということでperlで処理したいと思います。
ありがとうございました。

補足日時:2002/01/18 18:35
    • good
    • 0
この回答へのお礼

ご回答ありがとうございました。
まさにperlやりたかった内容です!
grepと比較検討してみたいと思います。
#見た目的にはperl処理かな ^ ^;)

お礼日時:2002/01/18 09:02

> また、systemコマンドでgrepを呼んだとすると、その結果をperlで処理するのはどうするのでしょうか?



パイプを使います。perl は普段使わないので、怪しいのですが、こんな感じになるはず。

open IN, "grep なんとかかんとか |" or die "error\n";
while ( <IN> ) {
  何か $_ を使った処理。例えば…
  print;
}
close IN;


> ファイルは1つです。その中で検索する文字列が40個あります。

ああ、そういうことなのね。ちょっと迷いますね。

sed で、一行一単語にばらしつつ、検索する文字列を含む行だけを抽出しておいて、その出力を perl で
処理してカウントして行くのが一番軽いかな?
    • good
    • 0
この回答へのお礼

さらなるご回答ありがとうございます。
パイプの使い方大変参考になりました。
sedのほうは、atonさんが回答していただいた処理と比較検討してみたいと思います。

お礼日時:2002/01/18 08:57

直接の回答にはならないかもしれません。



> それよりwcやgrep -cを40回行った方が早いのでしょうか?

wc や grep は、複数のファイルを一度に処理できますから、起動は一回だけで
済みます。

# 特定の単語を探すのであれば、wc には無理ですね。

perl もかなり早いんですが、(環境にもよりますが)grep なんかは、それなりに
速さを要求されてきて育ってきたプログラムですから、下手なスクリプトを書くよりは
ずーっと早いです。

もし探す文字が、固定で構わない(つまり、正規表現を使わない)のであれば、
fgrep を使うのが一番早いんじゃないかと思います。

この回答への補足

回答ありがとうございます。

>grep は、複数のファイルを一度に処理できますから、起動は一回だけで済みます。
>
ファイルは1つです。その中で検索する文字列が40個あります。
それぞれの個数を調べるにはやはり40回のgrepが必要ですか?

あと、その前後の処理をperlで書いてしまっているので、perl上で処理できるように
したいというのがあります。
また、systemコマンドでgrepを呼んだとすると、その結果をperlで処理するのはどうするのでしょうか?
grepの結果をファイルに一度結果を出力する必要があるのでしょうか?

補足日時:2002/01/15 19:08
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QCシェルで、文字列中(str)に、固定文字列(abc)の数を数える方法

Cシェルで、文字列中(str)に、固定文字列(abc)の数を数える方法を教えてください
たとえば、
set str = abcdabceabcd
set abc = abc
str中に、abcを現れる数(3)を求める方法を教えてください
Cシェルは詳しい方がいらっしゃいましたら、是非教えてお願いいたします

Aベストアンサー

別に詳しいって訳でも無いですが、リダイレクトしてテンポラリファイルに出力してfgrep等で数えるのが簡単かなーと思いますけど。

http://oshiete.goo.ne.jp/qa/198863.html

QLinuxシェルによる同一文字列のカウント集計

あるファイル中の同じ文字列の行をカウントして
それぞれの文字列が何回現れるか集計するシェルを作ろうとしています。
しかし、最後のグループの集計がうまくいきません。
入力ファイルはソート済みです。
スコープの問題なのかどうか良くわかりませんが、想定外の動きをします。
このシェルの修正もしくは、別のいい集計方法、
どちらでも歓迎です。よろしくお願いします。


書いてみたシェル
------------------
#!/bin/sh

TARGET_STR=`head -n 1 uniqData.txt`
declare -i COUNT=0

cat uniqData.txt | while read LINE_STR
do
if [ "${TARGET_STR}" = "${LINE_STR}" ]; then
COUNT=$COUNT+1
else
echo $TARGET_STR:$COUNT
TARGET_STR=${LINE_STR}
COUNT=1
fi
done

echo $TARGET_STR:$COUNT
------------------



入力ファイル
------------------
asd
asd
asd
dfg
dfg
gghhjj
gghhjj
gghhjj
gghhjj
ttyyuuu
ttyyuuu
ttyyuuu
wwee
------------------

期待出力
------------------
asd:3
dfg:2
gghhjj:4
ttyyuuu:3
wwee:1
------------------

実際の出力
------------------
asd:3
dfg:2
gghhjj:4
ttyyuuu:3
asd:0
------------------

あるファイル中の同じ文字列の行をカウントして
それぞれの文字列が何回現れるか集計するシェルを作ろうとしています。
しかし、最後のグループの集計がうまくいきません。
入力ファイルはソート済みです。
スコープの問題なのかどうか良くわかりませんが、想定外の動きをします。
このシェルの修正もしくは、別のいい集計方法、
どちらでも歓迎です。よろしくお願いします。


書いてみたシェル
------------------
#!/bin/sh

TARGET_STR=`head -n 1 uniqData.txt`
declare -i COUNT=0

cat uni...続きを読む

Aベストアンサー

回答としては#1の方法がベストだと思います。

参考までにシェルが希望通りに動作しないのは、
パイプ以降がサブシェルで動作するからです。
多分asdの行数が1行のときもうまくいかないのではないでしょうか?
解決方法としては以下のいずれかが考えられます。
1.変数をexportしてしまう。
2.シェルをbashに変更してwhileの部分も変更する。
while read LINE_STR
do
省略
done < uniqData.txt
3.シェルをkshとかに変更。

QBシェル 文字列に含まれる特定文字のカウント

文字列の中に特定の文字が何個含まれているのかを知りたいです。wcやgrep を使ってみましたが、うまくいきません。教えてください。
例えば「123456789abc1defg0123456789」 の中に「1」は3個含まれているってのを調べたいです。

Aベストアンサー

文字列の中には空白文字が無いとすると、bashの組み込み機能だけで出来ます。

#!/bin/bash
A=123456789abc1defg0123456789
B=/$A/ ←先頭や末尾に特定文字が含まれている場合の考慮
IFS=1 ←ここに特定文字(一文字に限る)
set -- $B
echo $(($#-1))

空白や記号が含まれている場合で、bashも無い場合
#!/bin/sh
A=123456789abc1defg0123456789
LENA=`expr length "$A"`
B=`echo "$A" | sed s/1//g` ←削除すると短くなる
LENB=`expr length "$B"`
echo `expr $LENA - $LENB`
こっちの方がわかりやすいか。

Qcshでsubstr

ヤマトです。

cshの文字列分割について質問します。
環境はRed Had Linux7.2です。

set DATA = A01/B/テスト文字列

のデータの5文字目の文字列は何か取得したいのですが、
substr($DATA,5,1)みたいな書き方は、
awkを使用してできるのでしょうか?

===sample.sh一部抜粋===
set DATA = A01/B/テスト文字列
set AAA = substr($DATA,5,1) ←(?)
echo $AAA

===結果===
B

教えて頂けると有り難く思います。宜しくお願いします。

Aベストアンサー

すみません、訂正です。

>set AAA = `echo $DATA | '{print substr($0,5,1)}'`

set AAA = `echo $DATA | awk '{print substr($0,5,1)}'`

肝心の AWK コマンドが抜けていました(^^;失礼しました。

Qgrepで検索文字列が完全一致した行だけ取り出す方法

grepの文字列検索で検索文字列が単語として、完全一致した行だけ取り出す方法はないでしょうか?

通常は
grep hoge hoge.txt

と打つと、hogeが含まれる行が出力されますが、今回は含まれる行ではなくて完全に文字列が一致した行だけ取り出したいのです。

例えばhoge.txtの中に
cc ghoge
kkl hogem
jjll hoge
という3行があったとしたら最後の行でhogeという文字が空白で区切られた行だけ取り出したいのです。

何かよい方法があれば教えてください

Aベストアンサー

-w オプションじゃだめですか?

参考URL:http://www.linux.or.jp/JM/html/GNU_grep/man1/grep.1.html

Qディレクトリの中身(ファイル)をコピーするコマンドは?(fedora)

こんにちは。
fedora core5を使っていてCPコマンドで困りました。
cp -R /home/aaa /home/bbb
と入力して、aaaというディレクトリの中身のファイルを全てbbbというディレクトリへコピーしようとしたのですが、これではaaaというディレクトリごとbbbへコピーされてしまい、/home/bbb/aaa みたいになってしまいます。

指定したディレクトリの中のファイルを全て別ディレクトリへコピーするときはどのように指定すればよいのでしょうか?

Aベストアンサー

カレントディレクトリが/homeとします。
cp ./aaa/* ./bbb/
とすればいいと思います。ドットファイルまでコピーしてくれるかどうかは自信がありません。manを読んで下さい。

Qシェルスクリプトでファイル内の数値文字列を数値として扱うには

失礼します。
シェルスクリプトでファイル内のテキスト(数値文字列)を取得して、それを使って計算するにはどうすれば良いでしょうか?

str:ファイル内のテキスト(数値文字列)

res=$(( $str + 1 ))

・エラー
")syntax error: invalid arithmetic operator (error token is "


よろしくお願いします。

Aベストアンサー

bashをご使用と判断して

res=$(( $str + 1 ))
ではなく、
res=$(( str + 1 ))
だと思います。

> exprもやってみたのですが、処理が遅くなるので使いません。
興味があって以下のシェルで検証してみました。

#!/bin/bash

str=1
i=0

echo 'Using $((str + 1))'
date '+%H:%M:%S.%N'

while [ $i -lt 10000 ]
do
str=$(( str + 1))
i=`expr $i + 1`
done

date '+%H:%M:%S.%N'

exit

$ ./test.sh
Using $((str + 1))
09:18:46.290418000
09:18:56.929345000
これをexprに書き換えたところ
$ ./test2.sh
Using expr
09:19:00.302748000
09:19:19.259990000

exprだと19秒ですが、$(( 演算 )) だと10秒程度なので、演算が多くなれば確かにexprは不利ですね。

bashをご使用と判断して

res=$(( $str + 1 ))
ではなく、
res=$(( str + 1 ))
だと思います。

> exprもやってみたのですが、処理が遅くなるので使いません。
興味があって以下のシェルで検証してみました。

#!/bin/bash

str=1
i=0

echo 'Using $((str + 1))'
date '+%H:%M:%S.%N'

while [ $i -lt 10000 ]
do
str=$(( str + 1))
i=`expr $i + 1`
done

date '+%H:%M:%S.%N'

exit

$ ./test.sh
Using $((str + 1))
09:18:46.290418000
09:18:56.929345000
これをe...続きを読む

QStatement ignored というエラー

Oracle 9iを使ってsqlファイルを実行させたところ、タイトルにあるように、
PL/SQL: SQL Statement ignored
というエラーメッセージが出力されました。
いろいろ検索してみると、これは、私にシステム権限がないことからおこるとあったのですが、
その設定変更の仕方がいまいちよくわかりませんでした。設定変更のしかたを教えていただけないでしょうか。
また、設定変更したことによって変わるのは私自身のシステム権限だけであって、他にコンピュータ(UNIX)を共有している人たちには影響はありませんよね?
立て続けに質問ばかりすみませんが、よろしくおねがいします。

Aベストアンサー

PL/SQLで権限がないということは、EXECUTE PROCEDUREシステム権限がないということでしょうか・・・。
前後のエラーも記載していただいた方が良いとは思いますが。

システム権限の付与方法は下記で行うことが可能です。
※ここでいう"ユーザ"はOracleユーザのことでスキーマとイコールです。
1.SYSTEMまたはSYS(DBA権限を持ったユーザ)でログイン
2.grant execute procedure to [対象ユーザ];
  または
  grant resource to [対象ユーザ];

以上で一応権限付与はできますが、どのような処理を行いたいかによって、これだけで解決するかどうかわかりません。
また、他の人への影響ですが、ユーザをどのように使用しているか、どのようなポリシーのシステムかによって異なります。(「私自身」というのが、セッションのことかスキーマのことかわかりませんでした。)
同じユーザを他の人と共通で使っていれば、もちろん他の人へ影響が出ますし、一人1ユーザ(スキーマ)で割当てられていれば、影響なく使えます。
「影響が出る」という意味は、セキュリティレベルが権限付与された分落ちるということで、機能的に使用できなくなることはありません。

なお、セッション単位で権限を割当てる方法はないと思っています。
付与した権限をセッション終了次第revokeすれば、元に戻るのではないでしょうか。

PL/SQLで権限がないということは、EXECUTE PROCEDUREシステム権限がないということでしょうか・・・。
前後のエラーも記載していただいた方が良いとは思いますが。

システム権限の付与方法は下記で行うことが可能です。
※ここでいう"ユーザ"はOracleユーザのことでスキーマとイコールです。
1.SYSTEMまたはSYS(DBA権限を持ったユーザ)でログイン
2.grant execute procedure to [対象ユーザ];
  または
  grant resource to [対象ユーザ];

以上で一応権限付与はできますが、どのような処理を...続きを読む

Q3つの表の外部結合

表A、B、Cの3つがあり、Aのすべての行を出力したいと考えています。
外部結合を用いるのだとは思うのですが、3つの表に対して行う場合の
書き方がわからず困っています。
ご教授いただけないでしょうか?
select * from a,b,c
where a.商品ID =b.商品ID (+) and b.商品ID (+) =c.商品ID (+)
としてみましたが、うまくいきませんでした。

Aベストアンサー

ansi構文の趣旨からいえば、結合条件と絞り込み条件は分けて書くので・・

select *
from a
left join b on (a.商品ID =b.商品ID)
left join c on (b.商品ID =c.商品ID)
where a.年月 = 任意の値

と書くのが一般的でしょうね。

QCシェルでのファイルからの入力について

あるファイルが最終行になるまでに繰り返し実行するシェルを作りたいです。
とりあえずファイル名を1行ごとに5行程度入れてあるファイル「filemei」を作成しました。
そのファイルからファイル名を順番に取り出し、lsをするものを作ってみたのですが、うまくいきません。
とりあえず、繰り返しにはwhileやforeach、ファイルの読み込みにはawkを使ってみたのですが...
どなたか分かるかたがいれば教えて下さい。
無知なので、質問自体が訳が分からない場合があると思いますが、ご勘弁願います。

Aベストアンサー

とりあえず、
set a = $<
で、標準入力からの入力が一行、変数aに入ります。
例えば入力が
abcde 12345
であれば
$a = ( abcde 12345 )
となります。
abcde, 12345 はそれぞれ
$a[1], $a[2]
で参照できます。
ですから、
 while ( 条件 )
  set line = $<
  $line を処理
 end
のようにすれば、標準入力からの入力を一行ずつ処理できます。
これを例えばcommandというスクリプトにして
command < file
のようにすれば、指定したファイルからの入力を一行ずつ処理できます。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報