- ベストアンサー
行頭が数字の行を表示するシェルスクリプト
- 最近シェルスクリプトの勉強をはじめまして、行頭が数字の行を表示するシェルスクリプトを作成しようと思いましたが、うまく動作しません。
- 表示させたいファイルは字幕ファイルの始めの10行程度で、英語の台詞が入っています。
- 作成したスクリプトは、行ごとに読み込んだ行が数字で始まっているかどうかを判定し、数字で始まっている行だけを表示するものです。しかし、正しく動作しません。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
とりあえず問題点とその理由を書き出しますと。 if の後の [ ] はtestコマンドのエイリアスなのですが、 testコマンドでは、数値としての比較あるいは文字そのものかの比較しかできないので、 ワイルドカードや、正規表現は使えません。 $ hoge=012 $ test $hoge = 012; echo $? ならば返値は0ですが、 $ test $hoge = 0*; echo $? みたいなことはできず返値は1となって不一致となります。 なので、ワイルドカードや正規表現を利用して判断基準を作りたいならば、 case構文を利用するか、あるいはgrepなどを利用する必要があります。 また、仮にtestコマンドでワイルドカードや正規表現が使えたとしても、 [0-9][0-9]では、目的のものには引っかかりません。 正規表現で 1改行 2改行 などをマッチさせたいならば、 $ grep '^[0-9]*$'なんてしないとかかりません。 次に、これは別に間違いではないのですが、 ファイルを<や<<でインプットとかヒアドキュメントすると、 それが最後にかかれるために、複雑になってくると、どれがどこを読んでいるのか分かりにくくなります。 必要ならばファイルは素直にcatの引数として渡したほうが無難でしょう。 以上を踏まえきちんといらないところを省いてやれば、 #!/bin/sh grep '^[0-9]*$' hoge.txt と、かけます。 この場合、ifもtestもヒアドキュメントもいらず、コマンド一回ですむスクリプトかどうか疑わしいもので十分なわけです。
その他の回答 (4)
- kmee
- ベストアンサー率55% (1857/3366)
修正です > [ (test)コマンドで eq は「文字列が等しい」です。 → eqなどという演算子は用意されていません。 = で「文字列が等しい」 -eqで「数値(整数)が等しい」です。 パターンマッチでは無いのは同様です。 > grep '^[0-9][0-9]*' $1 → 数字だけの行なら grep '^[0-9][0-9]*$' $1 でした。 ただ、既に指摘のあるように、「数字だけの行」なのか「数字で始まる行」なのかがはっきりしないので、どちらが正しいかわかりません
お礼
スミマセン -eq でした(使う必要もないけど・・・)
- Tacosan
- ベストアンサー率23% (3656/15482)
ちょっと確認: 「行頭が数字の行」には 00:00:03,600 --> 00:00:07,195 なども含まれるはずなんだけど, 「望む結果」に入っていないのはなぜ?
お礼
すみません、説明不足でしたね。 正確には「数字のみの行」でした。
- gtx456gtx
- ベストアンサー率18% (194/1035)
シェルでプログラムするのも良いですが、この場合は#1のgrepやSED、Perlなどのコマンドを活用するとより簡単に探せます。 SEDは、下記のような1行で終わりです(動作確認していないですが ^ ^;)。 $ SED -e '/^[0-9]/p' 意味 ・/^xxx/は、「//」が探すパターンを指定、「/^xxx/」はxxxで始まるパターンという意味 ・/[0-9]/は、0、1、2・・・、9を表現する正規表現 SEDの説明 http://itpro.nikkeibp.co.jp/article/COLUMN/20060228/231161/ SEDは、古くからあるツールですが、ご質問のような作業には最適なツールと思います。
お礼
回答ありがとうございます sedコマンドは行を削除するだけのコマンドだと思ってました
- kmee
- ベストアンサー率55% (1857/3366)
> if [ "$Line" eq [0-9][0-9] ] ここでエラーになったりしませんか? ・[ (test)コマンドで eq は「文字列が等しい」です。完全一致です。正規表現などのパターンマッチではありません ・[0-9][0-9] こういうものは、まず、ファイル名に展開されます。ls *.txt とかやったときには、「lsが *.txt にマッチするファイルを探す」のではなく、「シェルが*.txtにマッチするファイル名に展開してからlsを実行」します。実際に実行されれうのは、例えば ls a.txt b.txt c.txt とかになります。 この場合、数字2桁のファイル名がなければエラーになるか、そのまま[0-9][0-9]という文字列になります(設定による) パターンマッチさせたければ、case文を使うとか、grep等のコマンドを使うとかになります。 もっとも、grepを使うなら grep '^[0-9][0-9]*' $1 の1行で終わりですけど。 あと、while read line みたいなのは最後の手段って思っておいた方がいいですよ。大抵は 各種コマンド(grep,sed..)とパイプで効率よく記述できますから
お礼
回答ありがとうございます。 >[ (test)コマンドで eq は「文字列が等しい」です。完全一致です。正規表現などのパターンマッチではありません なるほど、勉強になります。 >もっとも、grepを使うなら grep '^[0-9][0-9]*' $1 の1行で終わりですけど そうします。スクリプトにする必要もありませんでしたね(笑) >あと、while read line みたいなのは最後の手段って思っておいた方がいいですよ 自分は、それが最高の手段だと思ってました、最後だったのですね(汗)
お礼
回答ありがとうございます >ファイルを<や<<でインプットとかヒアドキュメントすると、 それが最後にかかれるために、複雑になってくると、どれがどこを読んでいるのか分かりにくくなります。 今後の参考にします >以上を踏まえきちんといらないところを省いてやれば、 #!/bin/sh grep '^[0-9]*$' hoge.txt と、かけます。 この場合、ifもtestもヒアドキュメントもいらず、コマンド一回ですむスクリプトかどうか疑わしいもので十分なわけです。 そうですね、スクリプトにする必要もありませんね(笑)