重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

お世話になります。

現在テキスト・エディターで文字列の置換作業を行っております。
エディターで置換を行った後に、ターミナルで特定文字列の抽出作業を行っているのですが、文字列置換作業もターミナルから行う事ができれば、文字列置換と文字列抽出の一連の作業を全てターミナルで行う事が出来るため、可能であれば文字列置換もターミナルから行いたいと思っております。


現在エディターで行っている置換内容は下記の通りになっております。(正規表現利用)

/test/(apple.*?)/

\n\1\n

※「/test/(apple.*?)/」を「\n\1\n」に置換すると言う意味です。

これをターミナルコマンドから該当ファイル(ファイル名は「wordtest1.txt」)内の文字列を一括で置換するには、どのように記述すれば良いでしょうか?
置換後は別名ファイルで保存したいと思っています。
元ファイル「wordtest1.txt」を読み込んで文字列置換を行い、「wordtest2.txt」として保存。

お力を貸して頂ければ助かります。
よろしくお願い致します。

質問者からの補足コメント

  • うーん・・・

    やりたいことをまとめてみました。
    「wordtest1.txt」内の文字列から「/test/(apple.*?)/」を「\n\1\n」に置換して「wordtest2.txt」の名前で保存。

    次に「wordtest2.txt」内から「^apple.*$」となっている文字列を抽出して、「wordtest3.txt」として保存。
    grep -o ^apple.*$ wordtest2.txt > wordtest3.txt

    最後に、「wordtest3.txt」の抽出された文字列から重複文字列(重複行)を削除して、「wordtest4.txt」として保存。
    awk '!a[$0]++' wordtest3.txt > wordtest4.txt

    文字列置換と文字列抽出、重複文字列削除(重複行削除)を連続して行えたら良いと思っております。

      補足日時:2016/03/13 09:19
  • うーん・・・

    perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt ; grep -o ^apple.*$ wordtest2.txt > wordtest3.txt ; awk '!a[$0]++' wordtest3.txt > wordtest4.txt

    上記で上手く出来たと思ったのですが、再度実行してみたら上手く行かなくなってしまいました。
    どこかでミスをしているのかなぁ。。。

    No.2の回答に寄せられた補足コメントです。 補足日時:2016/03/13 13:50
  • うーん・・・

    何度も申し訳ありません。

    wordtest.shに
    perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt
    と記載して「sh -x wordtest.sh」と実行してみました。

    実行内容は
    + perl -npe 's|/test/(apple.*?)/|?n$1?n|;' wordtest1.txt
    と表示。
    出力されたwordtest2.txtの内容はwordtest1.txtと変わらずでした。

    逆スラッシュが「?」に変わってしまっているのが気になります。

    考えられる原因は分かりますでしょうか。

    No.3の回答に寄せられた補足コメントです。 補足日時:2016/03/14 11:06

A 回答 (5件)

perl には s/// による置き換えがあります。


これは エディタの置換機能に対応させると
s/検索パターン/置換文字列/
となります。パターンや置換文字列に / を含む場合、 パターン中の / を \/と書くか、区切り用の文字を / から別の文字に変えるかします。

正規表現は言語、コマンド等によって違うので注意しましょう。

よりくわしくは、PerlDoc 等を参考にしてください。

http://perldoc.jp/docs/perl/5.18.1/perlretut.pod
http://perldoc.jp/docs/perl/5.14.1/perlre.pod



おまけ:
○連続してコマンドを実行する方法:
→シェルスクリプトを使います。例えば

perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt
grep -o ^apple.*$ wordtest2.txt > wordtest3.txt
awk '!a[$0]++' wordtest3.txt > wordtest4.txt

というファイル wortest.sh を作って
sh wordtest.sh
で連続で行えます。

→ コマンドを ; で区切ると、1行で書いたものを連続で実行します
perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt ; grep -o ^apple.*$ wordtest2.txt > wordtest3.txt ; awk '!a[$0]++' wordtest3.txt > wordtest4.txt

→ 中間ファイル (wordtest2.txt, wordtest3.txt)が不要なら、パイプが使えます。
パイプは前段の標準出力と後段の標準入力を継げます
perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt grep -o '^apple.*$' | awk '!a[$0]++' > wordtest4.txt

→ 並び順が変ってよいのなら、 awk の部分は sortコマンドの -uオプションが使えます。
→ 3つの内容をperlで一つに纏めることができます。
この回答への補足あり
    • good
    • 0
この回答へのお礼

kmee様、ご教授ありがとうございます。

perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt ; grep -o ^apple.*$ wordtest2.txt > wordtest3.txt ; awk '!a[$0]++' wordtest3.txt > wordtest4.txt

上記の記述をwordtest.shに記述して「sh wordtest.sh」として実行したら上手く出来ました(^-^)


あと1つコマンドを追加したいと思ったのですが、上手く出来なかったためご教授頂ければ助かります。
「wordtest1.txt」についてですが、これは複数のファイルを結合して作成したファイルなのですが、この結合作業も一緒に行えたら良いと思っております。
現在は「cat test/* > wordtest1.txt」と打ち込んで実行して、「test」フォルダの中のファイルを全て結合して「wordtest1.txt」を作成しております。
; で区切ると連続で実行できると言うことだったので、下記のように記述して実行してみましたが上手く出来ませんでした。

cat test/* > wordtest1.txt ; perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt ; grep -o ^apple.*$ wordtest2.txt > wordtest3.txt ; awk '!a[$0]++' wordtest3.txt > wordtest4.txt

アドバイスをお願い致します。

お礼日時:2016/03/13 13:16

#2に書いたURL や


http://perldoc.jp/docs/perl/5.20.1/perlop.pod#Re …
「Perl 正規表現 置換」等で調べてみてください。

s|/test/(apple.*?)/|\n$1\n|g
と、gオプションを付けることで、1行に複数あった場合にその全てが対象になります。


どのエディタを使っているかがわかりませんが。
現在なら、無難なのはUTF-8だと思います。
    • good
    • 0
この回答へのお礼

何度も申し訳ありません。

最後にgを付けた所、無事に全て動作するようになりました。

長くアドバイス頂きありがとうございました。

お礼日時:2016/03/16 12:25

バックスラッシュと円記号にはややこしい歴史がありまして。


正しくASCIIコード0x5cのバックスラッシュでないと、プログラムとしては期待した動作をしてくれません。

od -t x1c wordtest.sh
で、各文字の文字コード付きのダンプリストが出力されます。
これで、バックスラッシュの上がどうなっているか、確認してください。

5cになっていなかったら、5cになるように工夫が必要です。
Option+\で入力してみるとか
保存に使ったエディタで、文字コードを変えてみるとか。
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。

od -t x1c wordtest.sh

上記を実行したところ、逆スラッシュが「200」と表示され「200」の上は「80」になっていました。
wordtest.shのエンコードをエディタで「windows,DOS」に変更したら、逆スラッシュとなり上には5cと表示されるようになりました。

これでwordtest.shを実行した所、最後までコマンドを実行する事が出来るようになりました。
ご指摘通りファイルのエンコード形式に問題があったみたいですね。
「Unicode UTF-8」「ISO 2022-JP」も同様に逆スラッシュ(5c)になりましたが、どのエンコード形式が無難なのでしょうか?


また1つ問題が出てきしてしまい、最後までコマンドは実行されて結果も出力されるのですが、エディターを使った場合と結果が異なってしまっています。
コマンドを1つ1つ実行して確かめた所、perlのコマンドの所で問題がありそうです。
perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt
上記コマンドを実行した結果のwordtest2.txtをエディターで開いて、「/test/(apple.*?)/」で検索すると全ての該当箇所が置換出来ていないようです。
エディターを使用した場合では、全て置換する事が出来ています。

考えられる原因は分かりますでしょうか(>_<)

お礼日時:2016/03/15 06:02

○ ; て継ぐのは、1行で書くためのものです。


ターミナルでコマンド入力するときとか。

ファイルに保存して実行させる場合には、1行に1コマンド書けば、 ; は不要です。

cat test/* > wordtest1.txt
perl -npe 's|/test/(apple.*?)/|\n$1\n|;' wordtest1.txt > wordtest2.txt
grep -o '^apple.*$' wordtest2.txt > wordtest3.txt
awk '!a[$0]++' wordtest3.txt > wordtest4.txt


○ ^apple.*$ のような文字列をそのまま書くと、*とか$とかがシェルで展開されることもあります。
引用符でくくる等するのがよいでしょう。

○「うまくいかない」だけだと判断しかねます。
・なにかエラーになっているなら、そのエラーを書く
・せっかく中間状態がファイルに残っているのですから、どのファイルが期待と違う調べる。
 そうすれば、どこに間違いがあるかの目安になる。
・sh -x wordtest.sh
 と-xオプションを付けると、実際に実行する内容が出力されるので、期待通りになっているか確認する
この回答への補足あり
    • good
    • 0

MacOSのターミナルでは、UNIX標準のものが使えます。



定番は sed
https://developer.apple.com/library/mac/document …

ただ、 *?はそのままsedでは使えないので、正規表現の機能が豊富な perl で「ワンライナー」というのがいいかもしれません。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
プログラムの知識がほとんど皆無のため、具体的にどのように記述すれば良いのかご教授頂ければ助かります。
よろしくお願い致します。

お礼日時:2016/03/13 08:59

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