検索を使用した独自のファイルペアの結合

検索を使用した独自のファイルペアの結合

かなり大量のファイルに対して一連の操作を実行する必要があります。簡単のために、ペアの猫のための簡単な作業に焦点を当てて、ペアリングとシェルスクリプトの最も簡単なペアリング部分を作成する方法について説明します。

A.txt、B.txt、C.txt、およびD.txtという4つのファイルがあり、基本的に次のような圧縮スクリプトを作成しようとしているとします。

 cat A.txt B.txt > AB.txt
 cat A.txt C.txt > AC.txt
 cat A.txt D.txt > AD.txt
 cat B.txt C.txt > BC.txt
 cat B.txt D.txt > BD.txt
 cat C.txt D.txt > CD.txt

各ユニークな組み合わせの出力を望んでおり、この基準によれば、AD.txtとDA.txtは「固有」ではありません。

しかし、私はシェルスクリプトよりも少し簡単にしたいと思います。ここでは、他のファイルセットに対してこれを行い、ディレクトリで実行してすべての一致を再帰的に見つけることができます。私は道を間違えて仕事を台無しにしたように見えました。

find "$PWD" -type f -iname "*.txt" -exec [[SOME MAGIC CODE CREATING PAIRS OF FILE NAMES]] {} \; 
 \ cat "$MAGICPAIRfile1".txt "$MAGICPAIRfile2".txt >  
 \ "$MAGICPAIRfile1"-"$MAGICPAIRfile2".txt 

これらの部分をいくつか実行しようと考えていました。 1つはファイル名をテキストバッファにダンプし(ファイル名文字列のバッファタイプが正しくないため、バッファが存在しない)、そのバッファを別のexec {} \;に渡すことでした。

しかし、他の人が良い考えを持っているかもしれないと思いましたか?

答え1

これが私の提案です。

#!/bin/bash
files="empty"
for i in A B C D ; do
    for j in B C D ; do
     fn="$i$j"
     nf="$( echo $fn | rev )"
     # if nn is 1 $nf wasn't found in $files
      nn=1
      for q in $files ; do
        if [[ "$q" == "$nf" ]] ; then
               nn=0
         fi
        done
        if  [[  $nn -eq 1 ]] && [[ "$fn" != "$nf" ]] 
        then
           echo "cat $i.txt $j.txt >$fn.txt"
        fi
        files="$fn $nf $files"
    done
done

答え2

コマンドのファイルパラメータをfind配列に保存できます。保存する前にこれを行うこともできますsort。ここでは、GNUユーティリティを必要とするnull区切り文字(-d ''for mapfile(== readarray)、-print0for find、および-zfor)が使用されます。sort

iそして、全長から最後まで二重リングを作り、組み合わせを作ります。ここでは、ファイルパラメータのすべての組み合わせを処理できます。ji+1

#!/bin/bash
mapfile -d '' arr < <(find . -type f -name '*.txt' -print0 | sort -z)

for ((i=0; i<"${#arr[@]}"; i++)); do
    for ((j=i+1; j<"${#arr[@]}"; j++)); do
        printf "Processing files: %s %s\n" "${arr[i]}" "${arr[j]}"
    done
done
Processing files: ./A.txt ./B.txt
Processing files: ./A.txt ./C.txt
Processing files: ./A.txt ./D.txt
Processing files: ./B.txt ./C.txt
Processing files: ./B.txt ./D.txt
Processing files: ./C.txt ./D.txt

特定の例では、catファイルと目的の出力ファイル名(両方とも同じディレクトリレベルにあると仮定)の場合を使用してfind ... -printf '%f\0'ファイル名のみを印刷し、パラメータ拡張を使用して部分文字列を削除してコマンドを生成できます。改行文字をファイル名区切り文字として使用するいくつかの修正バージョン:

#!/bin/bash
mapfile -t arr < <(find . -type f -name '*.txt' -printf "%f\n" | sort)

for ((i=0; i<"${#arr[@]}"; i++)); do
    for ((j=i+1; j<"${#arr[@]}"; j++)); do
        cat "${arr[i]}" "${arr[j]}" > "${arr[i]%.*}${arr[j]}"
    done
done

答え3

perlファイル名が「うまくいく」と仮定して使用できる場合:

find ... |
perl -0777 -MMath::Combinatorics -anE \
  'BEGIN{$,=" "}; say sort(@$_) for (combine(2, @F))' |
sort

入力時の出力A\nB\nC\nD\n:

A B
A C
A D
B C
B D
C D

例(GNU sed)を再生成するには:

... |
sed -E 's/([^.]+).([^ ]+) ([^.]+).([^ ]+)/cat \1.\2 \3.\4 > \1\3.\2/'
cat A.txt B.txt > AB.txt
cat A.txt C.txt > AC.txt
cat A.txt D.txt > AD.txt
cat B.txt C.txt > BC.txt
cat B.txt D.txt > BD.txt
cat C.txt D.txt > CD.txt

その後、パイプをシェルに接続するか、/eGNU sedのフラグを使用して実行できます。

関連情報