テーブル値でファイルを結合する

テーブル値でファイルを結合する

私はたくさんのファイルを持っていますが、各ファイルの名前には特定のパターンが含まれています。たとえば、ABC1234001一部のデータグループ(複数列)に関する情報が含まれています。また、次の表がありますinfo.tsv

group1    ABC1234001    ABC1234010
group2    ABC1234011    ABC1234018
group3    ABC1234019    ABC1234028
...       ...           ...

これには以下が含まれます。

  • 「グループ」列でグループを指定し、
  • 「最初のファイル」列は、対応するグループ情報を含む最初のファイルのパターン(アルファベット順)を指定し、
  • 「最後のファイル」列は、そのグループ情報を含む最後のファイルのパターン(アルファベット順)を指定します。

だから私がすべきことは、各グループのファイルを1つのファイルにマージすることです。

cat ABC123401{1..8}* >> group2.tsv

このファイルを読むときにgroup2を例にしてみましょうinfo.tsv。この例では、すべてのファイル(、、、、、、、、ABC1234011.tsv)が1つのファイルにリンクされていABC1234012.tsvます。ABC1234013.tsvABC1234014.tsvABC1234015.tsvABC1234016.tsvABC1234017.tsvABC1234018.tsvgroup2.tsv

私がしたいことは次のとおりです。

while read $file; do
  #assign columns to variables like $1="group", $2="firstfile", $3="lastfile"
  cat *{$2..$3}* > $1.tsv;
done < info.tsv

しかし、このメソッドの変数を繰り返し変更する方法がわかりません。おそらくawk使用する方が便利ですが、よくわかりません。スクリプトは、「最初のファイル」から「最後のファイル」まで、テーブル内の対応するファイルの内容を含む名前group1.tsvのファイルの束を生成する必要があります。group2.tsvこれを行うためのスクリプトの作成を手伝ってください。

答え1

以下のスクリプトは、リンクしたいすべてのファイルがパターンと一致すると想定しています*.tsv。すべてが一致することがわかっている場合は、ABC*.tsv代わりにスクリプトの先頭でそのパターンを使用できます*.tsv

さらに、スクリプトは、特定のグループに入るすべてのファイル名が、拡張されたリストの連続したサブリストとして生成されると仮定します*.tsv

#!/bin/sh

set -- *.tsv

while read -r group first last; do
        collect=false

        for name do
                if ! "$collect"; then
                        [ "$name" = "$first.tsv" ] || continue
                        collect=true
                fi

                if "$collect"; then
                        cat -- "$name"
                        [ "$name" = "$last.tsv" ] && break
                fi
        done >"$group.tsv"

done <info.tsv

スクリプトは、位置引数のリストを一致する名前のリストに設定します*.tsv。次に、各行の3つのフィールドをinfo.tsv変数groupfirstとして読み込みますlast

この方法で読み取った各行の位置引数info.tsvリストで、グループの最初の名前と一致する名前を検索します。この名前が見つかったら、collectリストの現在の場所から始まり、位置パラメータリストで指定されたファイルからデータを収集するようにスクリプトのロジックに指示するフラグを設定します。これは、グループの姓に対応する名前が見つかると終了します。

ここでは単純な文字列ではなくコマンドとして使用されますtruefalse変数に格納されている値が$collect実行されることif ! "$collect"は、スクリプトが2つのシェル組み込みコマンドのうちの1つを実行することを意味します。trueあるいは、falseシェルには、Pythonなどの他の言語と同様に、特別なtrueまたはfalseキーワードはありません。

テスト:

$ ls
script
$ touch ABC{1234001..1234030}.tsv
$ for name in ABC*.tsv; do printf 'Name: %s\n' "$name" >"$name"; done
$ cat ABC1234015.tsv
Name: ABC1234015.tsv
$ cat >info.tsv <<END_DATA
group1 ABC1234001 ABC1234010
group2 ABC1234025 ABC1234030
END_DATA
$ ./script
$ cat group1.tsv
Name: ABC1234001.tsv
Name: ABC1234002.tsv
Name: ABC1234003.tsv
Name: ABC1234004.tsv
Name: ABC1234005.tsv
Name: ABC1234006.tsv
Name: ABC1234007.tsv
Name: ABC1234008.tsv
Name: ABC1234009.tsv
Name: ABC1234010.tsv
$ cat group2.tsv
Name: ABC1234025.tsv
Name: ABC1234026.tsv
Name: ABC1234027.tsv
Name: ABC1234028.tsv
Name: ABC1234029.tsv
Name: ABC1234030.tsv

この回答の説明で述べたように、個人的な目的でこのスクリプトを開発した方法は、スクリプトを次のように作成することでした。

#!/bin/sh

while read -r group first last; do
        collect=false

        for name do
                filename=$( basename "$name" )

                if ! "$collect"; then
                        [ "$filename" = "$first.tsv" ] || continue
                        collect=true
                fi

                if "$collect"; then
                        cat -- "$name"
                        [ "$filename" = "$last.tsv" ] && break
                fi
        done >"$group.tsv"

done

set上部のコマンドの削除(コマンドライン引数に置き換えられます)とリダイレクトの削除info.tsv(コマンドラインのリダイレクトに置き換えられます)に注意してください。また、filenameコマンドラインで指定されたパス名のファイル名部分を保持する変数も導入されました。

次に、次のようにスクリプトを実行します。

$ ./script ABC*.tsv <info.tsv

私がこれを実装したのは、入力グループのリストがどこに保存されているのか、名前があるのか​​わからず、ファイル名(ファイル名サフィックスがABCある限り)やファイル名がどこにあるのか気にしないスクリプトです。.tsv保存されます。

答え2

あなたのアプローチは良いアイデアですが、残念ながら、変数は中かっこ拡張の内側で拡張されないため、うまくいきません。

$ echo {1..5}
1 2 3 4 5
$ a=1
$ b=5
$ echo {$a..$b}
{1..5}

次の方法を使用してこの問題を解決できますeval

sed 's/ABC//g' info.tsv | 
    while read -r group start end; do 
        files=( $(eval echo ABC{$start..$end}.tsv) )
        cat "${files[@]}" > "$group.tsv"; 
    done 

これにより、最初にファイルABCからすべてのインスタンスが削除され、数値を個別に取得できます。info.tsvこれは、あなたが示した正確なデータ構造を想定しています。ABCグループ名にも表示される場合は、これは壊れます。

削除後、ABC結果は、およびwhile3つの変数を読み取るループにパイプされます。その後、中かっこ拡張を呼び出す前に、拡張する変数に渡してファイル名のリストを取得できます。$group$start$endeval

$ eval echo ABC{1..5}
ABC1 ABC2 ABC3 ABC4 ABC5

の結果は、次への入力として渡される配列evalに保存されます。$filescat

cat "${files[@]}" > "$group.tsv";

答え3

私が正しく理解したなら、これはオプションです

$ while IFS= read -r i; do
    f=$(echo "$i" | cut -d' ' -f1)
    cat $(echo "$i" | cut -d' ' -f2- | sed -E 's/([0-9])\s+/\1.tsv /;s/([0-9])$/\1.tsv /') > "$f.txt"
  done < info.tsv

  • f=$(echo "$i" | cut -d' ' -f1)グループの名前を検索します。
  • cat $(cut -d' ' -f2- | sed -E 's/([0-9])\s+|([0-9])$/\1.tsv /g')この行のファイルのリストをリンクします。

関連情報