2010-04-23 17 views
112

Ich versuche, ein einfaches Skript zu schreiben, das den Inhalt in zwei Listen auflisten wird. Um es zu vereinfachen, verwenden wir ls als Beispiel. Stellen Sie sich "eins" und "zwei" Verzeichnisse vor.Schnittpunkt zweier Listen in Bash

 
one=`ls one` 
two=`ls two` 
intersection $one $two 

Ich bin immer noch ziemlich grün in Bash, also fühlen Sie sich frei zu korrigieren, wie ich das mache. Ich brauche nur einen Befehl, der alle Dateien in "Eins" und "Zwei" ausgibt. Sie müssen in beiden existieren. Sie könnten dies die "Kreuzung" zwischen "Eins" und "Zwei" nennen.

+0

Nichts beantwortet hier die Frage: Wie schneidet man zwei * Variablen * in einem Bash-Skript? – jameshfisher

+0

Scheint wie eine neue Frage meiner Meinung nach, diese Frage ist hier klar beantwortet. –

+0

Ein wohl nützlicher Ansatz ist im nahen duplizieren http://stackoverflow.com/questions/2312762/compare-difference-of-two-arrays-in-bash – tripleee

Antwort

182
comm -12 <(ls 1) <(ls 2) 
+22

Ich kann nicht glauben, dass ich 'comm' bis heute nicht kannte. Dies hat meine ganze Woche gemacht :) –

+11

'comm' erfordert die Eingänge sortiert werden. In diesem Fall sortiert 'ls' automatisch seine Ausgabe, aber andere Verwendungen müssen dies möglicherweise tun:' comm -12 <(einige Befehle | sort) <(ein anderer Befehl | sort) ' –

+7

NICHT VERWENDEN ls ' Ausgabe für alles. ls ist ein Tool zum interaktiven Betrachten von Verzeichnismetadaten. Alle Versuche, die Ausgabe von ls mit Code zu analysieren, sind fehlerhaft. Globs sind viel einfacher und korrekt: '' für die Datei in * .txt ''. Lesen http://mywiki.wooledge.org/ParsingLs –

27

Verwenden Sie den Befehl comm:

ls one | sort > /tmp/one_list 
ls two | sort > /tmp/two_list 
comm -12 /tmp/one_list /tmp/two_list 

„sort“ nicht wirklich benötigt wird, aber ich schließe es immer vor „comm“ nur für den Fall verwenden.

+4

Es ist gut, um es zu schließen, da sie sortiert werden muss und er hat nur ls als Beispiel benutzt. – Thor84no

2

Eine weniger effizient (als comm) Alternative:

cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d 
+1

Wenn Sie Debians/bin/dash oder eine andere nicht-Bash-Shell verwenden in Ihre Skripte können Sie Ketten Befehle Ausgang mit Klammern: '(ls 1; ls 2) | sort -u | uniq -d' – nitrogen

+0

Sie beschreiben Vereinigung, nicht Kreuzung –

+1

@ MikaëlMayer sollten Sie Flagge den Namen der Person.. Sie antworten, sonst wird angenommen, Sie bedeuten mir – Benubird

27

Lösung mit comm

comm ist groß, aber in der Tat muß mit sortierten Liste arbeiten. Und zum Glück hier benutzen wir ls die von ls Bash Manpage

Einträge sortieren alphabetisch, wenn keine -cftuSUX noch --sort.

comm -12 <(ls one) <(ls two) 

Alternative mit sort

Überschneidung von zwei Listen:

sort <(ls one) <(ls two) | uniq -d 

symmetrische Differenz von zwei Listen:

sort <(ls one) <(ls two) | uniq -u 

Bonus

mit ihm spielen;)

cd $(mktemp -d) && mkdir {one,two} && touch {one,two}/file_{1,2}{0..9} && touch two/file_3{0..9} 
+1

Anstelle von * ergänzen *, ich denke, das ist, was normalerweise * symmetrische Differenz * genannt wird. –

1

Join ist eine weitere gute Option am Eingang abhängig und gewünschte Ausgangs

join -j1 -a1 <(ls 1) <(ls 2) 
-2

Es gibt eine andere Stackoverflow Frage "Array Kreuzung in bash" welches als ein Duplikat davon gekennzeichnet ist. Es ist meiner Meinung nach nicht ganz dasselbe, da diese Frage über den Vergleich von zwei Bash-Arrays spricht, während sich diese Frage auf Bash-Dateien konzentriert. Eine einzeilige Antwort auf die Frage, die nun geschlossen ist, ist wie folgt:

# List1=(0 1 2 3 4 6 7 8 9 10 11 12) 
# List2=( 1 2 3 5 6 8 9 11) 
# List3=($(comm -12 <(echo ${List1[*]}| tr " " "\n"| sort) <(echo ${List2[*]} | tr " " "\n"| sort)| sort -g)) 
# echo ${List3[*]} 
1 2 3 6 8 9 11 

Comm Dienstprogramm ist ein alphanumerisches Sortieren, wohingegen die „Array Kreuzung in bash“ Antworten verwenden Zahlen; daher die Verwendung "sort" und "sort -g".

Verwandte Themen