次のような命名スタイルを持つ多くのファイルがあります。
WBM_MIROC_rcp8p5_mississippi.txt
WBM_GFDL_rcp8p5_nosoc_mississippi.txt
DBH_HADGEM_rcp4p5_co2_mississippi.txt
HMH_IPSL_rcp4p5_mississippi.txt
これらのファイルは次の形式の表を表します(一部のファイルにはタブ区切り文字があり、他のファイルにはスペース区切り文字があります)。
YEAR MONTH DAY RES
1971 1 1 1988
1971 1 2 3829
...
rcp8p5
名前に含まれるすべてのファイルを1つの大きなテーブルにグループ化したいと思いますrcp4p5
。名前に含まれるファイルに対して同じことを行います。しかし、最初の3つの列が常に同じ重複を避けるために、各ファイルに4つの列だけを貼り付けたいと思います。現在、次のスクリプトを使用しています。
ls |
awk -F_ '{ i=$1; m=$2; s=$3; u=$4;
if(f[s]=="")add = $0;
else add = sprintf("<(cut -f4 %s)",$0);
f[s] = f[s] " " add }
END{ for(insc in f)
printf "paste%s > out_%s.txt\n",f[insc],insc
}' |bash
理由はわかりませんが、出力が予想と異なります。次の出力があります。
YEAR MONTH DAY RES YEAR MONTH DAY RES YEAR MONTH DAY RES
1971 1 1 187 1971 1 1 143 1971 1 1 234
1971 1 2 321 1971 1 2 398 1971 1 1 754
...
代わりに、次のような出力が必要です。
YEAR MONTH DAY RES RES RES
1971 1 1 187 143 234
1971 1 2 321 398 754
誰でも私にヒントを与えることができれば良いでしょう!
答え1
最も可能性の高い答えは、データファイル列がタブで区切られず、スペースで区切られていることです。cat -vet
実際のタブが表示されている場所のいずれかを実行してこれを確認できます^I
。
スペースを区切り文字として使用するようにコマンドを変更するには、cut
argを追加する必要がありますが、すでに単一引用符とawkスクリプト内にあるので、次のように-d' '
変更する必要があります。sprintf(...)
sprintf("<(cut -d\" \" -f4 %s)",$0)
答え2
大きすぎないファイルの場合:
while read -r f_part
do
awk '
BEGIN{
SUBSEP=" "
}
NR==1{
for(i=2;i<ARGC;i++)
$(NF+1)=$NF
print
}
FNR==1{
next
}
{
RES[$1,$2,$3]=RES[$1,$2,$3] $4 " "
}
END{
for(i in RES)
print i, RES[i]
}' *_${f_part}_* > big_table_${f_part}
done < <(printf '%s\n' *_*_*_*txt | cut -d_ -f3 | sort -u)
または、ファイルの順序が正しいと確信している場合:
while read -r f_part
do
set -- *_${f_part}_*
sed -i 's/\s+/:/3;s/\s\+/\t/g;s/\s*$//' "$@"
while [ $# -gt 1 ]
do
join -t: $1 $2 > tmp
mv tmp big_table_${f_part}
shift 2
set -- big_table_${f_part} "$@"
done
sed 's/:/\t/g' big_table_${f_part}
done < <(printf '%s\n' *_*_*_*txt | cut -d_ -f3 | sort -u)
答え3
for f in rcp8p5 rcp4p5
do : >"$f.txt"
find . ! -name . -prune ! -type d -name "*_${f}_*txt" -exec \
sh -c '
printf "%s\t" YEAR MONTH DAY
printf "%.0sRES\t" "$@"; echo
sed -n "
/^[0-9]/!d;p;:n
n
/^[0-9]/s/.*[[:blank:]]//p
bn
" "$@" | paste
' -- {} + >>"$f.txt"
done
...私の考えでは、あなたが以前やっていたことについて私が間違っている可能性があるので、これが報酬になる可能性があります。これがうまくいくかどうかはわかりませんが、そうであればそうする必要があります。方法今やっているより速いです。
デフォルトでは、名前が一致するファイルのリストを取得するか、find
シェルに渡します。...8...
...4...
{} +
シェルはYEAR MONTH DAY
それぞれで始まり、その後に\t
abが続くヘッダー行を印刷し、引数と同じ数の列をRES
印刷します。
その後、sed
すべてのファイルパラメータをストリームに連結し、数字で始まる最初の行全体を印刷し、数字で始まるすべての後続行は最後のフィールドのみを印刷します。
sed
のすべての出力はに渡され、入力のすべての行をpaste
出力のABSに置き換えます。\n
\t
このバージョンが欲しい〜する新しいサブシェルを呼び出し、リスト内の各ファイルに対して新しいパイプを開くのはほとんど悪い考えなので、うまくいきます。
もしそうなら〜するただし、表の各グループに新しい行を追加してください。ARGMAX
文書化 - これはおそらく悪いことではありませんが、後で処理するのは簡単です。
答え4
また、次のことを行うことができます
arr=( *_rcp8p5_*.txt )
paste "${arr[@]}" | cut -f-4,$(seq -s, 8 4 $((4*${#arr[@]}))) >out_rcp8p5.txt
paste
これにより、すべてのファイル*_rcp8p5_*.txt
に対してフィールド1〜4とそれ以降の4番目のフィールドがすべて抽出されます。