質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

シェル

シェル(shell)はUnix や Linux 系のOSで使用されるコマンドインタプリタを指します。

Q&A

解決済

1回答

1617閲覧

シェルスクリプトでテキストの更新処理

退会済みユーザー

退会済みユーザー

総合スコア0

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

シェル

シェル(shell)はUnix や Linux 系のOSで使用されるコマンドインタプリタを指します。

0グッド

1クリップ

投稿2017/11/23 08:27

###前提・実現したいこと
初心者です。

TXT01 と TXT02 という2つのファイルがあります。

TXT01は下記のDATAが入っています
ID     status
0001      A
0002      A
0003      A
0004      A
0005    B

TXT02には下記のDATAです。
ID     status
0001     B
0002     B
0003     A

TXT02のレコードをTXT01に更新したいのですが、
状態の異なる0001と0002はA→Bに更新し、
0003は同じAでstatusが同じなのでエラーコードか
statusが同じですという戻り値を返したいということです。

bashかAWKでと思いますが、コードサンプルをご教授いただけると
大変助かります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

仕様が曖昧な点がありますが、適当に想像して書いてみました。

更新後のTXT01をTXT01.newへ次のように出力したいと仮定します。(awkにせよ何にせよTXT01を同時に入力と出力の対象とすることはできませんので出力は一旦TXT01.newへ行うわけです)

ID status 0001 B 0002 B 0003 ERROR 0004 A <--TXT02に出現しないデータはそのまま 0005 B

bash

1( 2 echo '-s-' 3 cat TXT2 4 echo '-e-' 5 cat TXT1 6) | awk ' 7/-s-/,/-e-/ { m[$1]=$2; next } 8/^ID/ { print; next } 9{ print $1" "((m[$1] != $2) ? $2 : "ERROR") }' > TXT1.new

いろいろ行儀が悪い点があります。(-s-,-e-を辞書mに登録してしまう点など・・・)


追記:

otnさんにコメントいただいたので平易と思われる方法を追記させていただきます。

bash

1awk ' 2!F { m[$1]=$2; next } 3/^ID/ { print; next } 4{ print $1" "((m[$1] != $2) ? $2 : "ERROR") } 5' TXT2 F=1 TXT1 > TXT1.new

断然分かり易いですね!(まだイケテナイ部分は残っているだろうとは思いますが・・・)

投稿2017/11/23 09:03

編集2017/11/23 11:34
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/11/23 09:31

大変ありがとうございます。もっとわかりやすく質問できるよう工夫します。 参考にやってみます。
otn

2017/11/23 11:20

awkで複数ファイルに別々の処理をしたいとき、普通はこうします。 awk '!F{ m[$1]=$2; next }~~' TXT2 F=1 TXT1
KSwordOfHaste

2017/11/23 11:25 編集

そんな技が! コメントありがとうございます。 --- If a filename on the command line has the form var=val it is treated as a variable assignment. この一文を長年気づかずに使ってきました・・・感謝です。
退会済みユーザー

退会済みユーザー

2017/11/23 11:33

ありがとうございます。 実は質問の仕方が悪く、TXT01の同一キー(ID)のstatusをファイル名そのままで TXT02のレコードと比較してA→Bに書き換えられないかという、質問でした。 TXT02のレコードとTXT01のレコードを比較して、異なっていたらUPDATEするという ことですが、DBならなんということはないのですが、ファイルでやろうとすると良くわからず KSさんの回答から、無理かなと思いましたが、もし別解があるなら、アドバイスいただけるとありがたいです。 sedでということかもと調べていましたが、辿りつけません。
KSwordOfHaste

2017/11/23 11:42 編集

一旦TXT01.newに出力した後で、 mv TXT01.new TXT01 とすればよいだけでは? --- もし他のファイルへ一時的に出力したくないなら、通常のLinuxコマンドではなくCで専用のコードを書く必要がある気がします。テキスト処理が得意なUnix/Linuxですが、特定のファイルを直接書き換えるようなコマンドはパイプラインで繋げにくく、使い勝手が悪くなるため大抵のコマンドはstdinからstdoutへのフィルターとして設計されている気がします。
退会済みユーザー

退会済みユーザー

2017/11/23 12:01

ありがとうございます。勉強になります。 どうもDBの発想が抜けず、TXT01のレコードが数千とかの時のパフォーマンスを気にしました。 頭の切り替えが必要だなと思いました。 .newから元のTXT01に戻すとき差分だけとか(意味ないかも、とも思いますが) いくつか試してみます、ありがとうございました。
KSwordOfHaste

2017/11/23 12:06 編集

> DBの発想が抜けず その気持ちはなんとなくわかる気がします。すごく巨大なテキストファイルならもう少し専用のプログラム・論理で立ち向かわなければならないかも知れませんが、例えば10万行ぐらいのものをバッチ処理すると考えると専用のプログラムを作るよりはフィルターの組み合わせ+最後にmvでも充分なパフォーマンスが出る気がします。色々試してみるとLinuxがすごく軽いOSであることを実感される気がします。
takasima20

2017/11/23 22:41

横から失礼 「どうしても」元ファイルを直接更新したいのなら vi の操作を作って与えればいけると思いますが 数千行とかいう話なら一時的にでもdatabaseを 経由して処理しちゃう方がいいんじゃないのかなあ という気がしました
退会済みユーザー

退会済みユーザー

2017/11/24 06:33

貴重なご意見ありがとうございます。 更新となるとDBは楽だと思います。 ゆえあって、脱DBに挑戦中でして、 やってみたところ1万行程度なら、NEWファイル 一瞬で終わりましたので、パフォーマンス気にすることは ないと思いました。 ファイルのデータ量を必要最低限に抑えるため どのようにデータを分割保持するかが、肝だと思っていますが シェルコマンドに不慣れで、今後ともご指導お願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問