Bir çizginin başında veya ortasında desen için açılma


9

Bu sorunun göründüğünden biraz daha az masum olduğunu düşünüyorum diyerek başlayacağım.

Ne yapmam gerekiyor: PATH ortam değişkeni içinde bir klasör olup olmadığını kontrol edin. Başlangıçta veya sonrasında olabilir. Sadece o klasörün orada olduğunu doğrulamam gerek.

Benim sorunuma bir örnek - hadi kullanalım /opt/gnome.


SENARYO 1: klasör YOLUN başında değil

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

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

Grep'in yakalanmaması için yeterince spesifik olması gerektiğini unutmayın /var/opt/gnome. Dolayısıyla kolon.


SENARYO 2: klasör PATH başlangıcında.

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

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

Bu benim sorunum - bu klasörle iki nokta üst üste veya satır başı aramam gerekiyor. Yapmak istediğim şu iki parantez ifadesinden biri:

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

ANCAK [^ve [:kendi anlamları var. Bu nedenle, yukarıdaki iki komut çalışmaz.

Bu iki senaryo için tek bir komutta grep edebileceğim bir yol var mı?


İçin grepping değiliz tarihi: Costas'ın yanıta Gilles en yorum çok, soruya geçerli olduğunu unutmayın /opt/gnome:ya /opt/gnome$, sen bulacaksınız /opt/gnome-fooya /opt/gnome/bar.
Scott

@Scott - Müdahale alanınıza dahil ettiğiniz sürece, herhangi bir ipi her zaman bu tür komplikasyonlar olmadan hattın başına ve kuyruğuna sabitleyebilirsiniz. Just likegrep '^\(any number of other matches:*:\)*my match\(:.*\)*$'
mikeserv

Yanıtlar:


10

PATHOrtam değişkeninin içeriğini, bir dosyada bir şey aramak yerine kontrol ediyorsanız grep, yanlış araçtır. Kabukta yapmak daha kolay (ve daha hızlı ve tartışmalı olarak daha okunabilir).

Bash, ksh ve zsh'da:

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

portably:

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

Kullanım :$PATH:yerine not edin $PATH; bu şekilde, bileşen, başında veya sonunda olsa bile, arama dizesindeki her zaman iki nokta üst üste ile çevrelenir $PATH.

Bir dosyanın bir satırında arama yapıyorsanız, yalnızca bir satırın başında veya iki nokta üst üste işaretinden sonra ve yalnızca sonundaysa , genişletilmiş normal ifadeyi (ör. Zorunlu grep -E) (^|:)/opt/gnome($|:)kullanabilirsiniz /opt/gnomeçizgi veya onu izleyen bir kolon.


8

Genişletilmiş düzenli ifadeleri yalnızca grep -E

Yanlış pozitiflerden kaçınmak isteyip istemediğinizi bulmaya çalıştığınız yolun başlangıcını ve sonunu eşleştirmeniz gerekir.

Baştaki örnekle eşleşir:

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

Ayrıca ortadaki örnekle eşleşir:

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

Yanlış pozitiflerden kaçınmak:

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

Orada eşleşme yok.

Kompakt ve zarif. Debian 7 üzerinde test edilmiştir.


1
egrepkaldırılan kullanımıdır grep -E(kaynak: man grep)
Anthon

Teşekkürler, bir cazibe gibi çalışır! Cevap olarak seçmedim, çünkü -w seçeneğinin biraz daha basit olduğunu düşünüyorum. Hayal ettiğimden bile daha basit!
JamesL

3
Uyarı. -wSeçeneği bazı sorunları var. Yalnızca rakamlar, harfler ve alt çizgi "kelimeler" olarak kabul edilir. Yani bazı olağandışı ancak olası karakterlerin başarısız olması. Örnek echo '/sbin:/usr/sbin:/var-/opt/gnome' | grep -w "/opt/gnome"ve echo '/sbin:/usr/sbin:/var./opt/gnome' | grep -w "/opt/gnome". Bunlar yanlış sonuçlar veriyor.
Luis Antolín Cano

1
Sen doğru yoldasın, ama yanlış pozitif hala var: /opt/gnome/somethingelse.
Gilles 'SO- kötü olmayı bırak'

1
Kesinlikle doğru. Sadece başlangıcı değil, sonu da açıkça önemsemeliyiz. Bunun sorunları çözdüğünü düşünüyorum echo "/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta" | grep -E "(:|^)/opt/gnome(:|$)". Cevabı düzenleme.
Luis Antolín Cano

7

Eğer evlenmek değilseniz grep, kullanabileceğiniz awkve kayıtlarını ayırmak:

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

5

Ayrıca kullanabilirsiniz

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

Böylece yol değişkeni ayrı satırlara bölünür (her yol için bir tane), böylece grep -xkesin sonuçlar elde edilebilir. Bu elbette ek bir işleme ihtiyaç duyduğu dezavantaja sahiptir tr. Ve içindeki bir klasör adı PATHyeni satır karakterleri içerdiğinde çalışmaz .


2

Cevap için yeterli mi bilmiyorum ama

grep -w "/opt/gnome"

ihtiyacınızı karşılayacak.

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

fakat

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

İki nokta üst üste sözcük olmayan karakterler olduğu için bu mükemmel çalışır. Teşekkürler!
JamesL

@ Sman865 Başka bir sebep daha var: çünkü /kelimenin bir parçası değil ama r.
Costas

2
Uyarı. Cevabımın yorumunda söylediğim gibi. Dizin adı için sözcük olmayan karakter olan yasal karakterler vardır. Bu yanlış sonuçlara yol açar. Bir dizin adının sonlandırılması normal değildir - ancak olabilir.
Luis Antolín Cano

4
@ Sman865 Yanlış pozitif: /opt/gnome-beta,, /home/bob/opt/gnome
Gilles 'SO- kötü olmayı bırak'

Çalışma örneği: 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

Seçeneğini için /opt/gnome(yeni çizgiler, sigara kelime karakterleri ile çevrili :, /vs) bu birini deneyin:

grep '\B/opt/gnome'

0

Bunu güvenilir ve az çaba harcayarak yapabilirsiniz grep. Yaygın olarak bulunan ve birçok çözümün zaten sunulduğu uzantılardan yararlanabilirsiniz, ancak temel regex ile bile kolayca yapılabilir, ancak ilk bakışta sezgisel olarak olmayabilir.

Temel regex ile - ve böylece grep- her zaman iki güvenilir çapa sahip olursunuz - hattın başı ve kuyruğu. Satırdaki konumundan bağımsız olarak bir eşleşmeyi ikisine birden sabitleyebilirsiniz :

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

grepsatırın başından, \(grouped\)alt ifadelerin bir sonraki sınırlayıcıdan sonra açık eşlemenizle ve karşılaşmanızın kuyruğundan aynı şekilde çizginin kuyruğuyla karşılaşması gerektiği kadar alt ifadelerin eşleştiği kadar eşleşir. Sizin açık maç eşleşti değilse açıkça başarısız ve hiçbir şey yazdırılır.

Ve bunu yapabilirsiniz, örneğin:

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

Kendin için gör:

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

ÇIKTI

/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt/gnomenot::::/opt/gnome

0

bir uç durum fark ettiniz ... satırın başlangıcında a: ifadesini zorlayarak önleyebilirsiniz:

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

veya yol tamsa, sınırlandırıldığından emin olmak için sonuna bir tane ekleyin:

 echo ":${PATH}:" | grep ":/opt/gnome:"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.