Bu soruyu yorumlamanın iki yolu vardır; Her iki vakayı da ele alacağım. Satırları görüntülemek isteyebilirsiniz:
- artık herhangi bir artık basamak sırasının parçası olmayan dört basamaklı bir sekans içeren veya
- Bu, dört basamaklı bir diziyi içerir ancak artık basamak dizisi içermez (ayrı olarak bile değil).
Örneğin, (1) görüntülenir 1234a56789
, ancak (2) görüntülenmez .
Dört basamaktan oluşan bir diziyi içeren tüm satırları, artık herhangi bir basamaklı dizinin bir parçası olmayan görüntülemek istiyorsanız, bunun bir yolu:
grep -P '(?<!\d)\d{4}(?!\d)' file
Bu , Ubuntu'nun ( GNU grep ) desteklediği Perl düzenli ifadelerini kullanır . Gibi bir metinle eşleşmeyecek, onunla aynı olan veya onun bir parçası olanla eşleşmeyecektir . Ama maç olacak in .grep
-P
12345
1234
2345
1234
1234a56789
Perl'de düzenli ifadeler:
\d
herhangi bir rakam (demek [0-9]
veya söylemek için kısa bir yoldur [[:digit:]]
) anlamına gelir .
x{4}
x
4 kez eşleşir . ( {
}
sözdizimi Perl düzenli ifadelerine özgü değildir; uzatılmış düzenli ifadelerde grep -E
de kullanılır.) Öyle \d{4}
de aynı \d\d\d\d
.
(?<!\d)
sıfır genişlikte bir negatif geriye dönük iddia. "Öncesinde olmadıkça" demek \d
.
(?!\d)
sıfır genişlikte negatif ileriye dönük bir iddiadır. "Takip etmediği sürece" demek \d
.
(?<!\d)
ve (?!\d)
dört basamaklı dizinin dışındaki metinle eşleşmeyin; bunun yerine (birlikte kullanıldığında), daha uzun bir rakam dizisinin bir parçasıysa, dört basamaklı bir dizinin kendisinden eşleşmesini önler.
En arkadan veya en ileriden yalnızca geriye doğru bakmak kullanmak yetersizdir, çünkü en sağdaki veya en soldaki dört basamaklı sıra yine de eşleşecektir.
Geriye dönük ve ileriye dönük iddiaları kullanmanın bir yararı, deseninizin çevresindeki metinle değil, yalnızca dört basamaklı dizilerle eşleşmesidir. Renk vurgulamayı kullanırken ( --color
seçenekle birlikte) bu yardımcı olur.
ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4
Ubuntu'da varsayılan olarak, her kullanıcının alias grep='grep --color=auto'
kendi ~.bashrc
dosyasında vardır . Eğer ile başlayan basit bir komut çalıştırdığınızda otomatik vurgulama rengi elde Yani grep
(zaman bu takma adlar genişletilir) ve standart çıktı olan bir terminal (bu nedir denetler). Maçlar tipik olarak kırmızı bir gölgede vurgulanır ( vermilyona yakın ), ancak bunu italik kalın olarak gösterdim. İşte bir ekran görüntüsü:--color=auto
Ve ayrıca grep
, satırın tamamını değil, yalnızca eşleşen metinleri yazdırabilirsiniz -o
:
ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123
Arkası Olmadan ve İleriye Doğru Varma Beyanları Olmadan Alternatif Yol
Ancak, eğer:
- Perl düzenli ifadesini kullanmak istemediği veya
grep
desteklemediği sistemler üzerinde de çalışan bir komuta ihtiyacınız var ve-P
- Özel olarak dört rakamla eşleşmenize gerek yoktur - bu genellikle amacınız yalnızca eşleşmeleri içeren satırları görüntülemekse böyle olur ve
- biraz daha az zarif bir çözüm ile tamam
... o zaman bunun yerine genişletilmiş düzenli bir ifadeyle bunu başarabilirsiniz :
grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file
Bu, dört hane ve sayı olmayan karakter - veya çizginin başına veya sonuna - çevrelenerek eşleşir. özellikle:
[0-9]
herhangi bir rakamla eşleşir (örneğin [[:digit:]]
veya \d
Perl normal ifadelerinde) ve {4}
"dört kez" anlamına gelir. Böylece [0-9]{4}
dört basamaklı bir dizilimle eşleşir.
[^0-9]
değil aralığında karakterle eşleşir 0
through 9
. Eşittir [^[:digit:]]
(veya \D
Perl düzenli ifadelerinde).
^
, [
]
parantez içinde görünmediğinde, satırın başlangıcıyla eşleşir. Benzer şekilde, $
bir satırın sonuyla eşleşir.
|
araçlar veya ve parantezler gruplama içindir (cebirdeki gibi). Böylece (^|[^0-9])
, satırın başlangıcı veya rakam olmayan bir karakterle ($|[^0-9])
eşleşir, satırın sonu veya rakam olmayan bir karakterle eşleşir.
Dolayısıyla eşleşmeler yalnızca [0-9]{4}
aynı anda olan dört basamaklı bir diziyi ( ) içeren satırlarda gerçekleşir :
- satırın başlangıcında veya öncesinde bir rakam olmayan (
(^|[^0-9])
) ve
- satırın sonunda veya rakamsız (
($|[^0-9])
) ile izlenir .
Öte yandan, dört basamaklı bir sıra içeren tüm satırları görüntülemek istiyorsanız, ancak dört basamaktan daha fazla bir sıra içermiyorsa (yalnızca dört basamaklı başka bir sıradan ayrı bir satır bile), ardından kavramsal olarak amaç, bir desenle eşleşen ama bir diğeriyle eşleşen çizgileri bulmak.
Bu nedenle, tek bir desenle bunu nasıl bilmek bile, şöyle bir şey kullanarak öneririm mat en , ikinci öneri grep
ayrı iki kalıpları için ing.
Bunu yaparken Perl düzenli ifadelerinin gelişmiş özelliklerinden hiçbirinden tam olarak yararlanamazsınız, bu yüzden bunları kullanmamayı tercih edebilirsiniz. Ancak yukarıdaki stile uygun olarak, şunun yerine (ve diş telleri) kullanarak mat'ın çözümünün kısaltılması :\d
[0-9]
grep -P '\d{4}' file | grep -Pv '\d{5}'
Kullandığı yana [0-9]
, mat yoludur daha taşınabilir - bu sistemlerde çalışacak grep
Perl düzenli ifadeler desteklemez. Kullanmak yerine [0-9]
(veya [[:digit:]]
) kullanırsanız \d
, ancak kullanmaya devam {
}
ederseniz, mat'ın taşınabilirliğini biraz daha net bir şekilde elde edersiniz:
grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'
Tek Desenli Alternatif Yol
Eğer gerçekten bir grep
komut tercih ederseniz
- Tek bir düzenli ifade kullanır ( yukarıdaki gibi
grep
bir boru ile iki saniye değil )
- en az bir dört basamak dizisi içeren satırları görüntülemek,
- fakat beş (veya daha fazla) hane dizisi içermez,
- ve sadece rakamları değil, tüm çizgiyi eşleştirmeyi umursamıyorsunuz (muhtemelen buna aldırmazsınız)
... sonra kullanabilirsiniz:
grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file
-x
Bayrak markaları grep
satırları gösterecektir burada tüm çizgi maçlar (yerine bir çizgi içeren bir maç).
Bir Perl düzenli ifadesi kullandım çünkü bence bu konudaki açıklığı \d
ve \D
netliğini önemli ölçüde arttırıyor. Ancak , grep
desteklemeyen sistemlerde taşınabilir bir şeye ihtiyacınız olursa -P
, bunları [0-9]
ve [^0-9]
(veya [[:digit:]]
ve ile [^[:digit]]
) ile değiştirebilirsiniz:
grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file
Bu normal ifadelerin çalışma şekli:
Ortada \d{4}
veya [0-9]{4}
dört basamaklı bir sekansla eşleşiyor. Bunlardan birden fazlasına sahip olabiliriz, ancak en az birine sahip olmamız gerekir.
Solda (\d{0,4}\D)*
veya ([0-9]{0,4}[^0-9])*
sıfır veya daha fazla ( *
) örnekle, dört basamaktan daha fazla olmayan, ardından rakam olmayanlar. Sıfır rakamlar (yani hiçbir şey) "dört rakamdan fazla değil" için bir olasılıktır. Bu (a) boş dize veya (b) rakamsız biten herhangi bir dize ve dörtten fazla rakam içermeyen dizilerle eşleşir .
Hemen merkezin \d{4}
(veya [0-9]{4}
) solundaki metin ya boş ya da rakamsız bir bit ile bitmesi gerektiğinden, bu, merkezin \d{4}
solunda başka bir (beşinci) rakam olan dört rakamla eşleşmesini önler .
Sağda (\D\d{0,4})*
veya ([^0-9][0-9]{0,4})*
sıfır veya daha fazla ( *
) rakamsız bir örnekle eşleşir ve ardından dört rakamdan fazla olmaz (daha önce olduğu gibi dört, üç, iki, bir veya hatta hiçbiri olmayabilir). Bu maçlar , (a) boş dize veya (b) herhangi bir dizi başlayan olmayan bir rakam olarak ve en fazla dört basamaklı bir dizilerini içermeyen.
Merkezin \d{4}
(veya [0-9]{4}
) hemen sağındaki metin ya boş olmalı ya da rakamsız bir rakamla başlamalıdır, bu, merkezin \d{4}
sağında başka bir (beşinci) rakam olan dört rakamla eşleşmesini önler .
Bu, bir yerde dört basamaklı bir dizinin bulunmasını ve hiçbir yerde beş veya daha fazla basamak bulunmamasını sağlar.
Bu şekilde yapmak kötü ya da yanlış değil. Ancak, belki de bu alternatifi değerlendirmenin en önemli nedeni , yukarıda ve Matt'in cevabında önerildiği gibi bunun yerine (veya benzerini) kullanmanın faydasını netleştirmesidir .grep -P '\d{4}' file | grep -Pv '\d{5}'
Bu şekilde amacınız, bir şeyi içeren ama bir başkasını içermeyen satırları seçmektir. Ayrıca, sözdizimi daha basittir (bu yüzden birçok okuyucu / bakıcı tarafından daha hızlı anlaşılabilir).
1234a12345
görüntülenmeli mi, görüntülenmemeli mi?