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

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

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

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

Q&A

解決済

3回答

4068閲覧

awk を使ったフィールドの置換

shotaroh

総合スコア23

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

0グッド

0クリップ

投稿2018/06/19 02:18

前提・実現したいこと

初心者です。
awk を使ったフィールドの置換について質問です。
特定のフィールド内に重複した要素がある時に識別番号を付与したいのですが、うまくいきません。

以下の gene_name "7SK" 1行目と2行目が重複しておりこのような行がいくつかあります。
そこで、それぞれに識別番号をつけ、7SK-0,7SK-1のようにしたいと考えております。

bash

1$ head -3 fantom_cat_stringent_kd.gtf| sort -f -k 6 -t ";" |awk -F\" '{print $0}'| less 2 3chr8 FANTOM gene 144623796 144624570 . + . gene_id "ENSG00000254144.2"; geneSuperClass "all_lncRNA"; geneClass "lncRNA_divergent"; geneSubClass "divergent_promoters"; gene_type "antisense"; gene_name "7SK"; coding_status "nonCoding"; cumulative_support "FANTOM:GENCODE"; geneCategory "p_lncRNA_divergent"; DHS_type "DHS_promoter"; 4chr21 FANTOM gene 26473444 26475653 . + . gene_id "ENSG00000232512.2"; geneSuperClass "all_lncRNA"; geneClass "lncRNA_intergenic"; geneSubClass "far_from_coding_genes"; gene_type "lincRNA"; gene_name "7SK"; coding_status "nonCoding"; cumulative_support "GENCODE:HUBDMAP"; geneCategory "__na"; DHS_type "not_DHS"; 5chr19 FANTOM gene 58856544 58864858 . - . gene_id "ENSG00000121410.7"; geneSuperClass "all_mRNA"; geneClass "coding_mRNA"; geneSubClass "protein_coding"; gene_type "protein_coding"; gene_name "A1BG"; coding_status "coding"; cumulative_support "FANTOM:GENCODE"; geneCategory "coding_mRNA"; DHS_type "DHS_promoter";

試したこと

置換したい識別番号付与済みのtxtファイルを用意して、

bash

1$ head -3 replace.txt 27SK 37SK-1 4A1BG 5 6$ n=`cat replace.txt` 7 8$ cat fantom_cat_stringent_kd.gtf| sort -f -k 6 -t ";" |awk -F\" '($12='${n}'){print $0}'|head 9awk: syntax error at source line 1 10 context is 11 >>> <<< 12 missing ) 13awk: bailing out at source line 1 14

としてみたのですがなかなかうまくいく方法が見つからないので、ご教授いただけると幸いです。

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

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

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

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

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

otn

2018/06/19 06:46

対象カラムは gene_name 限定ということでいいですか?
a_saitoh

2018/06/19 07:06

第17フィールドを書き換えるのは比較的簡単。 gene_nameが第16フィールド以外にも出てくるからそれを全部探すとやや面倒ですが。どちらでしょうか?あと、最初の出現を7Sk-0とするのではなく、7SK→7SK-1→7SK-2でいいなら置換したい識別番号付与済みのtxtを作らなくてもできます。
shotaroh

2018/06/19 07:13 編集

otn様 はい、gene_name をしめす「" "」で囲われた部分を書き換えたいということです。
shotaroh

2018/06/19 07:30

a_saitoh様  第17フィールドを書き換えるのでよいのですが、差し支えなければ後者のやり方もお教えいただけますでしょうか。また、識別できれば良いので7SK→7SK-1→7SK-2 でも問題ありません。
guest

回答3

0

わかりやすさのためにあえてコンパクトでない回りくどい書き方にしていますがこんな感じ。
重複があるものの初出に-0をつけない代わりにワンパスで(単語リストファイル作らずに)いけます。
すべての入力の$19はかならずgen_nameであるという手抜き前提です。

awk

1#!/bin/awk -f 2{ 3#出現回数を数える 4#初出なら加工せずに出力して次の行に 5if (++names[$20] ==1) { 6 print 7 next 8} 9 10#gene name欄の文字数を数える 11l=length($20) 12# ダブルクォートとセミコロンを除た部分を取り出し 13name=substr($20,2,l-3) 14#2回目以降の出現では「ハイフン回数」をつける 15gname = "\""name "-" names[name]"\";" 16 17#$20を置き換えたものを出力 18for(i=1;i<=19;i++) 19 printf "%s\t",$i 20printf "%s", gname 21for(i=21;i<=NF;i++) 22 printf "\t%s",$i 23printf "\n" 24} 25

投稿2018/06/21 02:05

a_saitoh

総合スコア702

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

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

shotaroh

2018/06/22 07:56

ありがとうございます。参考になりました。
guest

0

ベストアンサー

これでどうでしょう。
私の経験では、所定のキーワードが所定の場所に必ずあると決めつけるのは危険すぎるので、行ごとにgene_name探し出して置換する作戦にしています。

awk

1BEGIN{ 2 l = length("gene_name \""); 3} 4{ 5 match($0, /gene_name "[^"]*/) 6 if(RSTART>0){ 7 genename = substr($0, RSTART+l, RLENGTH-l) 8 printf "%s%s-%d%s\n", 9 substr($0, 0, RSTART+l-1), 10 genename, 11 c[genename], 12 substr($0, RSTART+l+length(genename)), 13 c[genename]++ 14 }else{ 15 print 16 } 17} 18

ちなみにperlならワンライナーで対処できそうです。

perl -pe 's/(gene_name ")([^"]+)/sprintf("$1$2-%d",$c{$2})/eg; $c{$2}++;' fantom_cat_stringent_kd.gtf > out.gtf

投稿2018/06/19 09:08

編集2018/06/19 13:51
KojiDoi

総合スコア13669

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

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

angel_p_57

2018/06/19 12:07

`$c{$2}++`ではないでしょうか。
KojiDoi

2018/06/19 13:52

ありがとうございます。修正しました。
shotaroh

2018/06/22 07:57

ありがとうございます。参考になりました。
guest

0

対象が何カラム目か数えるのが面倒なので、何カラム目にあっても良いようにしました。
1回では仕様通りは無理なので、ファイルを2回読みます。
1回目に重複する回数を数えて、2回目に2個以上重複した場合に書き換えます。
"で囲まれているので書き換えがめんどくさいです。";を置換します。

Bash

1awk '!F{for(i=1;i<NF;i++)if($i=="gene_name")A[$(i+1)]++} 2F{for(i=1;i<NF;i++){ 3 X=$(i+1) 4 if($i=="gene_name"&&A[X]>1){ 5 if(!B[X]) B[X]=0; 6 sub(/";/,"-" B[X] "\";", $(i+1)); 7 B[X]++; 8 } 9} 10print 11}' fantom_cat_stringent_kd.gtf F=1 fantom_cat_stringent_kd.gtf

投稿2018/06/19 07:50

編集2018/06/22 08:02
otn

総合スコア84423

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

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

shotaroh

2018/06/22 07:57

ありがとうございます。参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問