2016-07-09 15 views
1

Ich bin dabei, von Zsh zu Bash zu wechseln, und ich muss ein Bash-Skript erstellen, das doppelte Einträge in $PATH entfernen kann, ohne die Einträge neu zu ordnen (also keine sort -d Magie). zsh hat einige nette Array-Handling-Shortcuts, die es einfach machen, dies effizient zu tun, aber mir sind solche Verknüpfungen in bash nicht bekannt. Ich bin auf this answer gestoßen, was mich 90% des Weges dorthin gebracht hat, aber es gibt ein kleines Problem, das ich gerne besser verstehen würde. Es scheint, dass wenn ich diesen awk-Befehl ausführe, der letzte falsch bearbeitete Datensatz dem Muster entspricht.Awk Muster entspricht immer letzten Datensatz?

$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:cc 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb" 
aa:bb:cc:bb 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:" # note trailing colon 
aa:bb:cc: 

Ich verstehe nicht, awk gut genug, um zu wissen, warum es so verhält, aber ich habe es geschaffen, durch Verwendung eines Zwischen Array wie so um das Problem zu umgehen.

array=($(awk 'BEGIN{RS=":";ORS=" "}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:")) 
# Use a subshell to avoid modifying $IFS in current context 
echo $(export IFS=":"; echo "${array[*]}") 
aa:bb:cc 

Dies scheint eine suboptimale Lösung jedoch so meine Frage ist: Habe ich etwas falsch in dem awk-Befehl, der falsch positive Ergebnisse auf dem Endaufzeichnung verarbeitet verursacht?

Antwort

4

Der letzte Datensatz in Ihrer ursprünglichen Zeichenfolge ist cc\n, der sich von cc unterscheidet. Wenn sie nicht sicher, was in jeder Sprache in jedem Programm passiert, einige print-Anweisungen ist das Hinzufügen Schritt 1 zu Debugging/Untersuchung:

$ awk 'BEGIN{RS=ORS=":"} {print "<"$0">"}' <<<"aa:bb:cc:aa:bb:cc" 
<aa>:<bb>:<cc>:<aa>:<bb>:<cc 
>:$ 

Wenn Sie die RS wollen : oder \n dann Zustand sein, genau das (mit GNU awk mindestens):

$ awk 'BEGIN{RS="[:\n]"; ORS=":"} !a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:$ 

die $ in allen oben genannten ist meine Aufforderung.

+0

Gutes Beispiel zu sehen, was passiert. Aber könnten Sie erklären, warum eine neue Zeile an die Zeichenfolge angehängt wurde? –

+2

Das ist etwas, was bash macht, es bewirkt, dass sich 'cmd <<<" string "' genauso verhält wie 'echo" string "| cmd', aber ohne den zusätzlichen Befehl ('echo') und die Pipe. POSIX-Textverarbeitungstools (sed, awk, grep, etc.) funktionieren nur mit POSIX-Textdateien, ansonsten erhalten Sie undefiniertes Verhalten. Wenn also eine Datei oder ein Eingabestream nicht mit einem Zeilenumbruch endet, handelt es sich nicht um eine POSIX-Textdatei/stream, so dass ein abschließender Zeilenumbruch erforderlich ist, um das erwartete/gewünschte Verhalten zu erzeugen. –

+1

Danke! Ich habe jetzt ein besseres Verständnis dafür, warum das Problem auftritt, was mich dazu bringt, eine angemessene Lösung für das Problem zu finden. So klein ein Problem auch war, Ihre Antwort war sehr hilfreich für mich. – Christopher

0

Eine weitere mögliche Abhilfe statt Bash-Array-Lösung

$ echo "aa:bb:cc:aa:bb:cc" | tr ':' '\n' | awk '!a[$0]++' | paste -sd: 
aa:bb:cc 
Verwandte Themen