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

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

ただいまの
回答率

90.61%

  • bash

    621questions

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

  • AWK

    66questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 300

shotaroh

score 6

 前提・実現したいこと

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

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

$ head -3 fantom_cat_stringent_kd.gtf| sort -f -k 6 -t ";" |awk -F\" '{print $0}'| less

chr8    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";
chr21   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";
chr19   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ファイルを用意して、

$ head -3 replace.txt
7SK
7SK-1
A1BG

$ n=`cat replace.txt`

$ cat fantom_cat_stringent_kd.gtf| sort -f -k 6 -t ";" |awk -F\" '($12='${n}'){print $0}'|head
awk: syntax error at source line 1
 context is
     >>>  <<< 
    missing )
awk: bailing out at source line 1


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • otn

    2018/06/19 15:46

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

    キャンセル

  • a_saitoh

    2018/06/19 16:06

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

    キャンセル

  • shotaroh

    2018/06/19 16:12 編集

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

    キャンセル

  • shotaroh

    2018/06/19 16:30

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

    キャンセル

回答 3

checkベストアンサー

+1

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

BEGIN{
    l = length("gene_name \"");
}
{
    match($0, /gene_name "[^"]*/)
    if(RSTART>0){
        genename = substr($0, RSTART+l, RLENGTH-l)
        printf "%s%s-%d%s\n", 
            substr($0, 0, RSTART+l-1),
            genename,
            c[genename],
            substr($0, RSTART+l+length(genename)),
        c[genename]++ 
    }else{
        print
    }
}

ちなみに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 21:07

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

    キャンセル

  • 2018/06/19 22:52

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

    キャンセル

  • 2018/06/22 16:57

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

    キャンセル

+1

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

awk '!F{for(i=1;i<NF;i++)if($i=="gene_name")A[$(i+1)]++}
F{for(i=1;i<NF;i++){
    X=$(i+1)
    if($i=="gene_name"&&A[X]>1){
        if(!B[X]) B[X]=0;
        sub(/";/,"-" B[X] "\";", $(i+1));
        B[X]++;
    }
}
print
}' fantom_cat_stringent_kd.gtf F=1 fantom_cat_stringent_kd.gtf

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/22 16:57

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

    キャンセル

+1

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

#!/bin/awk -f
{
#出現回数を数える
#初出なら加工せずに出力して次の行に
if (++names[$20] ==1) {
        print
        next
}

#gene name欄の文字数を数える
l=length($20)
# ダブルクォートとセミコロンを除た部分を取り出し
name=substr($20,2,l-3)
#2回目以降の出現では「ハイフン回数」をつける
gname = "\""name "-" names[name]"\";"

#$20を置き換えたものを出力
for(i=1;i<=19;i++)
      printf "%s\t",$i
printf "%s", gname
for(i=21;i<=NF;i++) 
      printf "\t%s",$i
printf "\n"
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/22 16:56

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

    キャンセル

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

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    linuxで文字列検索

    シェルスクリプトで書いています. 以下のようなファイル(file.tsv)があった時,車を所有してかつ男性の行をa.txtに出力するにはどうすれば良いですか? また,年代順に並

  • 解決済

    アクセスログから1分ごとの訪問回数上位者の回数とIPアドレスをレポート

    Webサイトのアクセスログから、訪問上位者の訪問回数とIPアドレスを抜き出したいと考えています。 シェルスクリプトにして、cronで1分ごとに稼働させ、レポートを作ろうと考え

  • 解決済

    bashの文字列検索について

    bashで以下のようなスクリプトを実現しなければいけません。 txtファイルを1行ずつ読み込み、行内にある2つの文字列、1つは大文字アルファベット3文字、1つは整数3桁、それ

  • 解決済

    シェルのawk内で定義した変数や結果をAwk外で取り扱いたい

    表題の通りなのですが、AWKでテキスト処理を行った結果をAWK外で扱いたいです。 test.txt は以下のようにタテ並びの数字が羅列されており、これらの行を全て足した値を 

  • 受付中

    シェルスクリプトでファイルを結合

    Linux(シェル)初心者ですが、よろしくお願いします。 シェルを書く練習をしており、以下の場合のよい方法が思い浮かびません。 2種類のファイルA.txtとB.txtがあり

  • 解決済

    bashでソート

    前提・実現したいこと john.dat john.jpg dave_smith.dat dave_smith.jpg nick.dat nick.jpgというファイルがあって、d

  • 受付中

    awkで重複行の削除及びカウントを実施したい

    awkコマンドを用い、csvの中から重複した行を除外し、重複した件数が何件存在しているか確認できるコマンドはありますでしょうか? 例 sample.csv 以下の項目が存

  • 解決済

    エラーを無視して出力

    お世話になります。 ABC.txtの行数が1000行以上なら処理、以下なら何もしない このような処理を行おうとしています。 LINE=`wc -l ABC.txt |

同じタグがついた質問を見る

  • bash

    621questions

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

  • AWK

    66questions

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