異なるディレクトリにある複数のファイルをリンクします。

異なるディレクトリにある複数のファイルをリンクします。

異なるディレクトリの複数のファイルをリンクしたいと思います。

ディレクトリ1:Chr1この例では4つのファイルが含まれています。

ABC.1 
DEF.1
GHI.1 
JKL.1 

カタログ 2:Chr2

ABC.2  
DEF.2 
GHI.2
JKL.2 

22のディレクトリがあります。各ファイルには20個の列とヘッダーがあります。ヘッダーはすべてのファイルに同じです。

すべてを1つのファイル(すべてのディレクトリ内のすべてのファイルをリンクするグローバル出力ファイル)にリンクしたいと思います。

私はこれを試しましたが、うまくいきません。

cat */Chr{1..22}/*.{1..22} > */final_file

ファイルがないため、「該当するファイルやディレクトリはありません」と表示されます。たとえば、* .1〜21はchr22ディレクトリにあるファイルです。

どんな考えがありますか?よろしくお願いします。

答え1

ただzshシェルを使用してください:

cat -- */Chr<1-22>/*.<1-22>(n) > final_file

は10進数の範囲に一致するglob演算子であり、glob修飾子はglob拡張が数値でソートされるようにするオプションを切り替えzshます。<x-y>nnumericglobsort

他のシェルでは、次のことができます。

zsh -c 'cat -- */Chr<1-22>/*.<1-22>(n) > final_file'

最初のファイルを除くすべてのヘッダーをスキップし、GNUまたはBusinessBoxの実装tail(Linuxをカーネルとして使用するシステムで最も一般的です)を想定するには、次のようにします。

(){
  cat < $1; shift; (($#)) && tail -qn +2 -- "$@"
} */Chr<1-22>/*.<1-22>(n) > final_file 

答え2

アプローチの問題は、繰り返されるワイルドカードが「同期的に」(=「拡張」)解釈されず、コマンドラインで発生するたびに再解釈され、独立していることです。したがって、機能するには入れ子になったシェルループを使用する必要があります。

次のシェルスクリプトを試してみてください。機能を使用することに注意してくださいbash(あなたの質問は使用中のシェルをカバーしません)

#!/bin/bash

hdr=0   # initialize variable to keep track of whether the header is already printed

# loop over directories
for d in Chr*
do
    # extract trailing number from dir name by removing 'Chr' part (bash feature!)
    n="${d#Chr}"

    # loop over all files
    for f in "$d/"*".$n"
    do
       if (( hdr == 0 )) # if header wasn't printed yet, output entire file
       then
           cat "$f" > final_file
           hdr=1
       else              # otherwise, output file content starting with line 2
           tail -n +2 "$f" >> final_file
       fi
    done
done

スクリプト名をconcatenate.sh実行可能ファイルとして指定し、すべてのサブディレクトリがあるディレクトリで実行できますChr{1..22}final_fileこのディレクトリにも作成されます。

あまりにも遠くにテストすることはできませんが、何も壊さないでください...

答え3

すべてのサブディレクトリのすべてのファイルをキャプチャするには、Chr.*次のものを使用できます。

cat Chr*/* >final_file

そのディレクトリ名のサフィックスと一致するように各サブディレクトリのファイルセットを制限する必要がある場合(したがってChr1一致するファイルのみを考慮*.1)、ループが必要です。

shopt nullglob    # This is bash-specific
for i in {1..22}
do
    cat Chr$i/*.$i
done >final_file

このオプションは、shopt nullglob一致しないワイルドカード文字をリテラルアスタリスクとして残すのではなく、ワイルドカード文字を削除するようにシェルに指示します。

あるいは、リンクされたファイルから最初のヘッダー行を除くすべてを省略したいように見えるので、この拡張ループはそれを処理できます。

first=yes
for i in {1..22}
do
    for f in Chr$i/*.$i
    do
        [[ -n "$first" ]] && head -n1 "$f" && first=
        cat "$f"
    done
done >final_file

または、ヘッダー行が最初のファイルの最初の行として存在し、その後に見つかるすべての場所から削除できる場合は、次の構造を使用して削除できます。

for i in {1..22}
do
    cat Chr$i/*.$i
done |
    awk '$0 != header { print } header == "" { header = $0 }' >final_file

関連情報