web-dev-qa-db-ja.com

同じヘッダーで複数のファイルを連結する

同じヘッダーとその下の異なるベクターを持つ複数のファイルがあります。すべてを連結する必要がありますが、最初のファイルのヘッダーのみを連結したいのですが、他のヘッダーはすべて同じなので連結したくありません。

例:file1.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C

file2.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
D
E 
F

私は出力が必要です

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
D
E 
F

Rでスクリプトを記述できますが、シェルで必要ですか?

29
Jana

Rでそれを行う方法を知っている場合は、必ずRで実行してください。従来のUNIXツールでは、これは最も自然にawkで行われます。

_awk '
    FNR==1 && NR!=1 { while (/^<header>/) getline; }
    1 {print}
' file*.txt >all.txt
_

Awkスクリプトの最初の行は、すべてのファイル(_FNR==1_)の最初の行でもある場合を除いて、ファイル(_NR==1_)の最初の行と一致します。これらの条件が満たされると、式while (/^<header>/) getline;が実行されます。これにより、現在の行が正規表現_^<header>_に一致する限り、awkは別の行を読み取り続けます(現在の行をスキップします)。 awkスクリプトの2行目は、以前にスキップされた行を除くすべてを出力します。

tailheadを使用した、上記の「cat+grep」と同様の別のソリューション:

  1. 最初のファイルのヘッダーを出力に書き込みます。

    head -2 file1.txt > all.txt
    

    -head -2は、ファイルの最初の2行を取得します。

  2. すべてのファイルの内容を追加します。

    tail -n +3 -q file*.txt >> all.txt
    

    --n +3は、3行目から最後までtail印刷行を作成し、-qは、ヘッダーをファイル名で印刷しないように指示します(manを読み取る)、>>はファイルに追加し、>として上書きしません。

そして、両方のコマンドを1行で入力できることを確認してください。

head -2 file1.txt > all.txt; tail -n +3 -q file*.txt >> all.txt

または;の代わりに、成功チェックのためにそれらの間に&&を挿入します。

44
xealits

これを試してください:

$ cat file1.txt; grep -v "^<header" file2.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C
D
E 
F

注意

  • -vフラグは grep の一致を反転することを意味します
  • ^ in [〜#〜] regex [〜#〜] 、は文字列の始まりを意味します
  • あなたがたくさんのファイルを持っているなら、あなたはすることができます

array=( files*.txt )
{ cat ${array[@]:0:1}; grep -v "^<header" ${array[@]:1}; } > new_file.txt

bash 配列スライステクニックです。

4
Gilles Quenot

sedを使用すると、短い(必ずしも速いとは限りません):

sed -e '3,${/^<header>/d' -e '}' file*.txt > all.txt

これにより、3行目から始まる<header>...で始まるすべての行が削除されるため、最初のヘッダーは保持され、他のヘッダーは削除されます。ヘッダーの行数が異なる場合は、それに応じてコマンドを調整します(たとえば、6行のヘッダーの場合、7ではなく3を使用します)。
ヘッダーの行数が不明な場合は、次のように試すことができます。

sed '1{
: again
n
/^<header>/b again
}
/^<header>/d
' file*.txt > all.txt
1
don_crissti

tailコマンド(少なくともGNUでは)には、指定された数の最初の行をスキップするオプションがあります。 2行目以降を印刷するには、つまり1行のヘッダーをスキップするには、次のようにします。tail -n+2 myfile

したがって、Bashで最初のファイルの2行のヘッダーを保持し、2番目のファイルのヘッダーを保持しないようにするには、次のようにします。

cat file1.txt <(tail -n+3 file2.txt) > combined.txt

または、多くのファイルの場合:

head -n1 file1.txt > combined.txt
for fname in *.txt
do
    tail -n+3 $fname >> combined.txt
done

特定の文字列がすべてのヘッダー行に存在するが、残りの入力ファイルには存在しないことがわかっている場合、grep -vは、スプートニクが示したように、より単純なアプローチです。

1
etal

array =(* .txt); head -1 $ {array [0]}> all.txt;尾-n +2 -q $ {array [@]:0} >> all.txt

結合/連結が必要な同じヘッダーの.txtファイルを含むフォルダーを使用していると仮定すると、このコードは、txtファイルをすべて1つのヘッダーだけでall.txtに結合します。最初の行(セミコロンで区切られた行)はすべてのテキストファイルを収集して連結し、2行目は最初のtxtファイルのヘッダーをall.txtに出力し、最後の行は収集したすべてのテキストファイルを連結しますヘッダーなしで(2行目以降から連結を開始することにより)、それをall.txtに追加します。

0
Eric