2017-01-13 3 views
0

Ich habe einige .txt Dateien in dir1:Prozessgruppen Dateipaare aus mehreren Verzeichnissen

file_name_FOO31101.txt 
file_name_FOO31102.txt 
file_name_FOO31103.txt 
file_name_FOO31104.txt 

und einige relevante foo.txt Dateien in dir2:

file_name_FOO31101_foo.txt 
file_name_FOO31102_foo.txt 
file_name_FOO31103_foo.txt 
file_name_FOO31104_foo.txt 

ich schließlich in der Lage sein wollen, ein anrufen Programm für Paare von Dateien, so dass:

Iteration 1

program_call \ 
    --txt file_name_FOO31101.txt,file_name_FOO31102.txt \ 
    --foo file_name_FOO31101_foo.txt,file_name_FOO31102_foo.txt \ 
    --bar file_name_FOO31101_bar.txt,file_name_FOO31102_bar.txt 

Iteration 2

program_call \ 
     --txt file_name_FOO31103.txt,file_name_FOO31104.txt \ 
     --foo file_name_FOO31103_foo.txt,file_name_FOO31104_foo.txt \ 
     --bar file_name_FOO31103_bar.txt,file_name_FOO31104_bar.txt 

D.h.
file_name_FOO31101.txt,file_name_FOO31102.txt
file_name_FOO31103.txt,file_name_FOO31104.txt
aber nicht
file_name_FOO31102.txt,file_name_FOO31103.txt

Eine Antwort von einem question I posted yesterday hat mich begonnen:

#!/bin/bash 

txt_files=/path/to/txt 
foo_files=/path/to/foo/files 

set -- "$txt_files"/*.txt 

[[ -e $1 || -L $1 ]] || { echo "No .txt files found in $txt_files" >&2; exit 1; } 

# $# = number of command line arguments passed to the script 
while (($# > 1)); do 

    stem=$(basename "${1}") 
    output_base=$(echo $stem | cut -d '_' -f 1,2,3) # split on '_' and save ID 

    echo "-> Processing pairs of txt files : $1,$2" 

    # Add files to array 
    txt1+=($1) 
    txt2+=($2) 

    shift; shift 

done 

(($#)) && echo "Left over file $1 still exists" 

Und dann (nicht einen besseren Weg, dies zu tun, zu wissen) Ich wiederhole die gleiche Schleife für die foo Dateien in dir2:

set -- "$foo_files"/*_foo.txt 

[[ -e $1 || -L $1 ]] || { echo "No foo.txt files found in $foo_files" >&2; exit 1; } 

# $# = number of command line arguments passed to the script 
while (($# > 1)); do 

    stem=$(basename "${1}") 
    output_base=$(echo $stem | cut -d '_' -f 1,2,3) # split on '_' and save ID 

    # Add files to array 
    foo1+=($1) 
    foo2+=($2) 

    echo "-> Processing pairs of foo.txt files : $1,$2" 

    shift; shift 

done 

(($#)) && echo "Left over file $1 still exists" 

und dann über eines der Arrays iterieren und Call-Programm (alle gleich lang sein müssen):

# Seeing as all arrays must be the same length, loop over one and print out corresponding values for others 
for ((i=0;i<${#txt1[@]};++i)); do 
    printf "program_call --txt %s,%s --foo %s,%s\n" "${txt1[i]}" "${txt2[i]}" "${foo1[i]}" "${foo2[i]}" 
done 

die im Grunde scheint zu funktionieren, Druck:

program_call --txt /path/to/txt/file_name_FOO31101.txt,/path/to/txt/file_name_FOO31102.txt --foo /path/to/foo/files/file_name_FOO31101_foo.txt,/path/to/foo/files/file_name_FOO31102_foo.txt 
program_call --txt /path/to/txt/file_name_FOO31103.txt,/path/to/txt/file_name_FOO31104.txt --foo /path/to/foo/files/file_name_FOO31103_foo.txt,/path/to/foo/files/file_name_FOO31104_foo.txt 

jedoch Ich vermute, dass die Verwendung der gleichen While-Schleife für alle verschiedenen Dirs eine schlechte Möglichkeit ist, dieses Ergebnis zu erzielen, insbesondere wenn ich weitere Optionen in meinem Programmaufruf hinzufügen möchte (z. B. file_name_FOO31101_bar.txt ...).

Ist das eine vernünftige Vorgehensweise?

+0

Gibt es eine Frage? Ich sehe Dinge gut funktionieren – Inian

Antwort

0

Ihre Intuition ist richtig: Es gibt schnellere Wege als bash Schleifen und Arrays.

hier, wie aufzulisten und die Dateien in beiden Verzeichnissen zu sortieren:

find txt foo -type f -name "*.txt" | sort -t'/' -k2,2 

Ausgang:

txt/a_0001.txt 
foo/a_0001_foo.txt 
txt/a_0002.txt 
foo/a_0002_foo.txt 
txt/a_0003.txt 
foo/a_0003_foo.txt 
txt/a_0004.txt 
foo/a_0004_foo.txt 
... 

nächstes, unter der Annahme, dass es keine zusätzliche oder fehlende Dateien in einem der Verzeichnisse sind, können Sie erhalten können 4/Zeile mit awk:

find txt foo -type f -name "*.txt" | sort -t'/' -k2,2 | 
    awk '{printf $1" "; if(NR%4==0)printf "\n"}' 

Ausgabe:

txt/a_0001.txt foo/a_0001_foo.txt txt/a_0002.txt foo/a_0002_foo.txt 
txt/a_0003.txt foo/a_0003_foo.txt txt/a_0004.txt foo/a_0004_foo.txt 
txt/a_0005.txt foo/a_0005_foo.txt txt/a_0006.txt foo/a_0006_foo.txt 
... 

nächsten, könnten Sie einen anderen awk erneut, um sie verwenden und die Befehlsfolgen machen:

find txt foo -type f -name "*.txt" | sort -t'/' -k2,2 | 
    awk '{printf $1" "; if(NR%4==0)printf "\n"}' | 
    awk '{print "program_call --txt "$1","$3" --foo "$2","$4}' 

Ausgang:

program_call --txt txt/a_0001.txt,txt/a_0002.txt --foo foo/a_0001_foo.txt,foo/a_0002_foo.txt 
program_call --txt txt/a_0003.txt,txt/a_0004.txt --foo foo/a_0003_foo.txt,foo/a_0004_foo.txt 
... 

Benchmark 500 Befehlsfolgen aus 2000-Dateien zu machen mit Fugus Code gegen find|sort|awk|awk:

bash loops & arrays 10.070s 
find|sort|awk|awk  0.019s 

, die so schnell :)

Sie anstelle von Schleifen durch die Verwendung Rohren Zeit über 500x ist sparen können auch die Befehlsfolgen ausführen:

find txt foo -type f -name "*.txt" | ... | sh 

und in der Regel noch mehr Zeit durch Rohrleitungen Befehle stattdessen GNU parallel :

find txt foo -type f -name "*.txt" | ... | parallel 

(Sie parallel installieren müssen, wenn es nicht bereits auf Ihrem System ist.)

Verwandte Themen