İf ifadesine grep komutuyla dize araması nasıl yapılır?


11

İki dosyada birden fazla dizeyi aramak istiyorum. Her iki dosyada da bir dize bulunursa, bir şey yapın. Bir dize yalnızca bir dosyada bulunursa, başka bir şey yapın.

Komutlarım bir sonraki:

####This is for the affirmative sentence in both files
if grep -qw "$users" "$file1" && grep -qw "$users" "$file2"; then

####This is for the affirmative sentence in only one file, and negative for the other one
if grep -qw "$users" "$file1" ! grep -qw "$users" "$file2"; then

ifadeleri reddetmenin ve doğrulamanın yolu doğru mu? pd KSH kabuğunu kullanıyorum.

Şimdiden teşekkür ederim.

Yanıtlar:


11

Bunu dene:

if grep -wq -- "$user" "$file1" && grep -wq -- "$user" "$file2" ; then
   echo "string avail in both files"
elif grep -wq -- "$user" "$file1" "$file2"; then
   echo "string avail in only one file"
fi
  • grep kalıpları birden fazla dosyada arayabilir, bu nedenle bir OR / NOT operatörü kullanmaya gerek yoktur.

Her komutta "-wq" ile "-qw" arasında minimum bir fark var mı?
Mareyes

2
Hayır, her ikisi de grep için -q ve -w seçenekleri sunar.
glenn jackman

3
Değişken genişlemede neden hiç teklif yok?
D. Ben Knoble

@ D.BenKnoble doğru mu: "$ user" "$ file1"?
Mareyes

1
@Mareyes evet bu doğru
D. Ben Knoble

13

Başka seçenek:

grep -qw -- "$users" "$file1"; in_file1=$?
grep -qw -- "$users" "$file2"; in_file2=$?

case "${in_file1},${in_file2}" in
    0,0) echo found in both files ;;
    0,*) echo only in file1 ;;
    *,0) echo only in file2 ;;
      *) echo in neither file ;;
esac

Hey isteğe bağlı yol için teşekkür ederim. Yeterince iyi çalışıyor !! sahip olduğum başka bir senaryoda mükemmel çalışıyor.
Mareyes

Bu güzel bir fikir! Her zaman öğrenme.
Joe

7
n=0

#Or if you have more files to check, you can put your while here. 
grep -qw -- "$users" "$file1" && ((n++))
grep -qw -- "$users" "$file2" && ((n++))

case $n in 
   1) 
       echo "Only one file with the string"
    ;;
   2)
       echo "The two files are with the string"
   ;;
   0)
       echo "No one file with the string"
   ;;
   *)
       echo "Strange..."
   ;;
esac 

Not: ((n++))ksh uzantısıdır ( zshve tarafından da desteklenir bash). POSIX shsözdiziminde n=$((n + 1))bunun yerine ihtiyacınız olacaktır .


Oh üzgünüm ((n ++)) yerine $ ((n ++)) yazıyordum. Unutmak.
Luciano Andress Martini

1
Not n=$((n++))için n değerini değiştirmek asla olacak n++olan sonrası artış: O geri akım değeri , n, daha sonra kademeli olarak N; sonra değişkeni orijinal n olan döndürülen değere ayarlarsınız.
glenn jackman

Dosya adlarınızın yeni satır içermediğini varsayabilir local IFS=$'\n'; matches=( $(grep -lw "$users" "$file1" "$file2") )ve kullanabilirsiniz case "${#matches[@]" in. @glenn: Bu fikir, birden fazla çağrıyı önlemek için cevabınız için de geçerlidir grep. Borulama grep -l | wc -lda işe yarayacaktı.
Peter Cordes

@Peter, ayrı bir yanıt IMO olarak yazmaya değer.
Stephen Kitt

@StephenKitt: Yapmayacaktım çünkü rastgele dosya adı karakterlerini işlemek için kurşun geçirmez bir yol bulamadım. Ama buna değer olduğunu düşündüğün için, yine de yazdım.
Peter Cordes

2

Dosya adlarınız satırsonu içermiyorsa, grep'in grepeşleşen dosyaların adlarını yazdırmasını ve sonuçları saymasını sağlayarak birden fazla çağrıyı önleyebilirsiniz .

 local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
 matches=( $(grep -lw "$users" "$file1" "$file2") )

Eşleşme sayısı "${#matches[@]}".

Burada kullanmanın bir yolu olabilir grep --null -lw, ancak çıktıyı nasıl ayrıştırılacağından emin değilim . Bash yerine var=( array elements )bir \0sınırlayıcı kullanmanın bir yolu yoktur \n. Belki de bashın mapfileyerleşimi bunu yapabilir mi? Ama muhtemelen hayır, çünkü ayırıcıyı ile belirtirsiniz -d string.


Yapabilirsiniz count=$(grep -l | wc -l), ancak sonra iki harici işleminiz vardır, böylece grepiki dosyayı ayrı ayrı da çalıştırabilirsiniz . (Arasındaki fark grepgenel wcbaşlangıç yükü her ayrı bir işlem başlatmak için çatal + exec + Dinamik bağlayıcı malzeme ile karşılaştırıldığında küçüktür).

Ayrıca, hangi dosyanın eşleştiğini wc -lde bulamazsınız .


Bir dizide yakalanan sonuçlar ile, zaten istediğiniz gibi olabilir veya tam olarak 1 eşleşme varsa, bunun ilk giriş olup olmadığını kontrol edebilirsiniz.

local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
matches=( $(grep -lw "$users" "$file1" "$file2") )

# print the matching filenames
[[ -n $matches ]] && printf  'match in %s\n'  "${matches[@]}"

# figure out which input position the name came from, if there's exactly 1.
if [[ "${#matches[@]" -eq 1 ]]; then
    if [[ $matches == "$file1" ]];then
        echo "match in file1"
    else
        echo "match in file2"
    fi
fi

$matcheskısayol ${matches[0]}, ilk dizi elemanıdır.


@StephenKitt: Demek istediğim -z, hayır -0, demek istedim . Evet \0, cevapta daha önce bahsettiğim gibi dosya adlarını ayrılmış olarak yazdırmak için grep alacaktı , ancak bunu ayrıştırmak için nasıl bash alabilirsiniz ? Doğrudan bash IFS=$'\0'ile find -print0stil çıktısı ayarlayamaz veya başka bir şey yapamazsınız .
Peter Cordes

Evet, çok hızlı okudum, bu paragrafı kaçırdım ve bir şeyler düşünmedim (bu yüzden yorumumu sildim). Bir yol olabilir, ama şimdi bir tane düşünemiyorum ve dediğin gibi grep, yine de başa çıkmak için sadece birkaç s olduğunda çözümü çok karmaşık hale getirmeye değmez .
Stephen Kitt

1
mapfile -d $'\0'bir tür işler, ama yeni satırları boşluklarla değiştirir (ayarlamayı denemedim IFS).
Stephen Kitt
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.