私はたくさんのファイルを持っていますが、各ファイルの名前には特定のパターンが含まれています。たとえば、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.tsv
ABC1234014.tsv
ABC1234015.tsv
ABC1234016.tsv
ABC1234017.tsv
ABC1234018.tsv
group2.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
変数group
とfirst
として読み込みますlast
。
この方法で読み取った各行の位置引数info.tsv
リストで、グループの最初の名前と一致する名前を検索します。この名前が見つかったら、collect
リストの現在の場所から始まり、位置パラメータリストで指定されたファイルからデータを収集するようにスクリプトのロジックに指示するフラグを設定します。これは、グループの姓に対応する名前が見つかると終了します。
ここでは単純な文字列ではなくコマンドとして使用されますtrue
。false
変数に格納されている値が$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
結果は、およびwhile
3つの変数を読み取るループにパイプされます。その後、中かっこ拡張を呼び出す前に、拡張する変数に渡してファイル名のリストを取得できます。$group
$start
$end
eval
$ eval echo ABC{1..5}
ABC1 ABC2 ABC3 ABC4 ABC5
の結果は、次への入力として渡される配列eval
に保存されます。$files
cat
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')
この行のファイルのリストをリンクします。