Greifen Sie nach dem Muster am Anfang oder in der Mitte einer Linie

9

Ich beginne damit, dass ich denke, dass dieses Problem etwas weniger unschuldig ist, als es sich anhört.

Was ich tun muss: Suchen Sie nach einem Ordner in der Umgebungsvariablen PATH. Es könnte am Anfang oder irgendwo danach sein. Ich muss nur überprüfen, ob dieser Ordner vorhanden ist.

Beispiel für mein Problem - verwenden wir /opt/gnome.


SZENARIO 1: Ordner befindet sich nicht am Anfang von PATH

# echo "$PATH"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

# echo "$PATH" | grep ":/opt/gnome"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

Beachten Sie, dass der grep spezifisch genug sein muss, damit er nicht abfängt /var/opt/gnome. Daher der Doppelpunkt.


SZENARIO 2: Ordner befindet sich am Anfang von PATH.

# echo "$PATH"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

# echo "$PATH" | grep "^/opt/gnome"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

Dies ist mein Problem - ich muss mit diesem Ordner nach einem Doppelpunkt oder einem Zeilenanfang suchen. Was ich tun möchte, ist einer dieser beiden Klammerausdrücke:

# echo $PATH | grep "[^:]/opt/gnome"
# echo $PATH | grep "[:^]/opt/gnome"

ABER [^und [:haben ihre eigenen Bedeutungen. Daher funktionieren die beiden obigen Befehle nicht.

Gibt es eine Möglichkeit, diese beiden Szenarien in einem Befehl zu erfassen?

JamesL
quelle
Beachten Sie, dass Gilles 'Kommentar zu Costas' Antwort auch für die Frage gilt: Da Sie nicht nach /opt/gnome:oder /opt/gnome$suchen, werden Sie /opt/gnome-foooder finden /opt/gnome/bar.
Scott
@Scott - Solange Sie den dazwischenliegenden Raum in Ihr Match einbeziehen, können Sie jederzeit eine beliebige Schnur ohne solche Komplikationen am Kopf und Schwanz der Linie verankern. Genau wiegrep '^\(any number of other matches:*:\)*my match\(:.*\)*$'
MikeServ

Antworten:

10

Wenn Sie den Inhalt der PATHUmgebungsvariablen überprüfen , anstatt nach etwas in einer Datei zu suchen, grepist dies das falsche Tool. Es ist einfacher (und schneller und wohl besser lesbar), dies in der Shell zu tun.

In bash, ksh und zsh:

if [[ :$PATH: = *:/opt/gnome:* ]]; then
 : # already there
else
  PATH=$PATH:/opt/gnome
fi

Tragbar:

case :$PATH: in
  *:/opt/gnome:*) :;; # already there
  *) PATH=$PATH:/opt/gnome;;
esac

Beachten Sie die Verwendung von :$PATH:eher als $PATH; Auf diese Weise ist die Komponente immer von Doppelpunkten in der Suchzeichenfolge umgeben, selbst wenn sie am Anfang oder Ende von war $PATH.

Wenn Sie eine Zeile einer Datei durchsuchen, können Sie den erweiterten regulären Ausdruck (dh erforderlich grep -E) verwenden, (^|:)/opt/gnome($|:)um eine Übereinstimmung zu erzielen , /opt/gnomejedoch nur, wenn er entweder am Anfang einer Zeile oder nach einem Doppelpunkt steht und nur am Ende von die Linie oder gefolgt von einem Doppelpunkt.

Gilles 'SO - hör auf böse zu sein'
quelle
8

Sie können erweiterte reguläre Ausdrücke verwenden, indem Sie einfach verwenden grep -E

Sie müssen den Anfang und das Ende des Pfads abgleichen, den Sie suchen, um Fehlalarme zu vermeiden.

Entspricht der Instanz am Anfang:

$ TEST=/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

Entspricht auch der Instanz in der Mitte:

$ TEST=/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

Vermeiden von Fehlalarmen:

$ TEST="/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta"
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"

Keine Übereinstimmungen dort.

Kompakt und elegant. Getestet auf Debian 7.

Luis Antolín Cano
quelle
1
egrepist deprecated Einsatz grep -E(Quelle: man grep)
Anthon
Danke, funktioniert wie ein Zauber! Ich habe es jedoch nicht als Antwort gewählt, da ich denke, dass die Option -w etwas einfacher ist. Noch einfacher als ich es mir ursprünglich vorgestellt hatte!
JamesL
3
Warnung. Die -wOption hat einige Probleme. Nur Ziffern, Buchstaben und der Unterstrich gelten als "Wörter". Einige ungewöhnliche, aber mögliche Zeichen lassen es scheitern. Beispiel echo '/sbin:/usr/sbin:/var-/opt/gnome' | grep -w "/opt/gnome"und echo '/sbin:/usr/sbin:/var./opt/gnome' | grep -w "/opt/gnome". Diese liefern falsche Ergebnisse.
Luis Antolín Cano
1
Sie sind auf dem richtigen Weg, aber es gibt immer noch Fehlalarme : /opt/gnome/somethingelse.
Gilles 'SO - hör auf böse zu sein'
1
Ganz recht. Wir sollten uns explizit um das Ende kümmern, nicht nur um den Anfang. Ich denke, dass dies die Probleme behebt echo "/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta" | grep -E "(:|^)/opt/gnome(:|$)". Antwort bearbeiten.
Luis Antolín Cano
7

Wenn Sie nicht verheiratet sind grep, können Sie awkdie Datensätze verwenden und trennen:

awk 'BEGIN {RS=":"} /^\/opt\/gnome$/'
Jasonwryan
quelle
5

Sie könnten auch verwenden

echo "$PATH" | tr ':' '\n' | grep -x "/opt/gnome"

Dadurch wird die Pfadvariable in separate Zeilen aufgeteilt (eine pro Pfad), sodass grep -xnach genauen Ergebnissen gesucht werden kann. Dies hat natürlich den Nachteil, dass dafür ein zusätzlicher Prozess erforderlich ist tr. Und es funktioniert nicht, wenn ein PATHOrdnername in Zeilenumbruchzeichen enthält.

TBrandt
quelle
2

Ich weiß nicht, ob es für eine Antwort ausreicht, aber

grep -w "/opt/gnome"

wird Ihr Bedürfnis befriedigen.

echo '/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome
echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome

aber

echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep "/opt/gnome" -o
/opt/gnome
/opt/gnome
Costas
quelle
Dies funktioniert perfekt, da Doppelpunkte keine Wortzeichen sind. Vielen Dank!
JamesL
@ Sman865 Es gibt noch einen anderen Grund: weil /es kein Teil des Wortes ist, sondern rist.
Costas
2
Warnung. Wie ich beim Kommentar zu meiner Antwort sagte. Es gibt zulässige Zeichen für einen Verzeichnisnamen, bei denen es sich nicht um Wortzeichen handelt. Das führte zu falschen Ergebnissen. Es ist nicht üblich, einen Verzeichnisnamen zu beenden - aber es könnte passieren.
Luis Antolín Cano
4
Falsch positive @ Sman865: /opt/gnome-beta, /home/bob/opt/gnome, ...
Gilles 'SO- Anschlag Sein Übel'
Nicht funktionierender Fall: grep -w /usr/local -o <<< /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games------/usr/local /usr/local /usr/local
Pabouk
0

So wählen Sie /opt/gnomevon Nicht-Wort - Zeichen umgeben (neue Linien, :, /etc) , versuchen Sie dieses:

grep '\B/opt/gnome'
jimmij
quelle
0

Sie können dies zuverlässig und mit geringem Aufwand tun grep. Sie können Erweiterungen nutzen, die weit verbreitet sind und von denen bereits viele Lösungen angeboten wurden, aber selbst mit Basis-Regex ist dies einfach, obwohl dies auf den ersten Blick möglicherweise nicht intuitiv möglich ist.

Mit Basic Regex - und so mit grep- haben Sie immer zwei zuverlässige Anker - den Kopf und das Ende der Linie. Sie können eine Übereinstimmung an beiden verankern, unabhängig von ihrer Position auf der Linie :

grep '^\(ignore case, delimiter\)*match\(delimiter, ignore case\)*$'

grepEs werden vom Kopf der Zeile so viele Vorkommen der \(grouped\)Unterausdrücke abgeglichen, wie erforderlich sind, um als nächstes auf Ihr Trennzeichen und dann auf Ihre explizite Übereinstimmung zu treffen , und vom Ende Ihrer Übereinstimmung bis zum Ende der Zeile auf dieselbe Weise. Wenn Ihre explizite Übereinstimmung nicht explizit übereinstimmt, schlägt sie fehl und gibt nichts aus.

Und so könnten Sie zum Beispiel tun:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$'

Überzeugen Sie sich selbst:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$
' <<\INPUT
/opt/gnome-beta
/opt/gnome
/home/bob/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt-gnome-beta
/opt/gnomenot::::/opt/gnome
INPUT

AUSGABE

/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt/gnomenot::::/opt/gnome
mikeserv
quelle
0

Sie haben einen Randfall bemerkt ... Sie könnten ihn vermeiden, indem Sie die Erscheinung eines: am Anfang der Zeile erzwingen:

 echo ":$PATH" | grep ":/opt/gnome"

oder wenn der Pfad genau ist, fügen Sie am Ende auch einen hinzu, um sicherzustellen, dass er begrenzt ist:

 echo ":${PATH}:" | grep ":/opt/gnome:"
Olivier Dulac
quelle