sabit bir dizgiyi satırın başında selamlama


20

grep "^$1"ama nasıl "$1"grep içindeki herhangi bir karakteri özel olarak yorumlamıyor?

Yoksa daha iyi bir yol var mı?

Düzenleme: Aramak istemiyorum '^$1'ama sadece bir satırın başında ise eşleştirilmesi gereken dinamik olarak eklenen bir sabit dize için. Demek istediğim bu $1.


Örneğin, çift tırnak yerine tek tırnak kullanmaya çalıştınız grep '^$1'mı? Yoksa merminin $1genişlemesini önlemek istediğiniz anlamına mı gelmediniz?
mnille

@mnille '^ $ 1' için arama yapmak istemiyorum, ancak yalnızca satırın başındaysa eşleştirilmesi gereken dinamik olarak eklenen bir sabit dize için. 1 $ demek istediđim bu.
PSkocik

3
Siz de yapabilirsiniz grepama önce dizenizdeki herhangi bir özel karakterden kaçmanız gerekecek, örneğinprintf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
don_crissti

@don_crissti diğer cevaplardan daha iyi. Bir tane yapmak ister misin?
roaima

@roaima - Biliyorum ama burada zaten bir sürü cevap var ve bu (vars içindeki özel karakterlerden kaçmak) bir şey (ve diğer birkaç kullanıcı) oldukça uzun süredir eve çekiçleniyor ... Her zaman ekleyebilirsiniz isterseniz cevabınıza yanıt verin ve yorumu burada kaldıracağım (eksik parantezleri eklemeyi unutmayın).
don_crissti

Yanıtlar:


7

Bunu kullanarak bir yol düşünemiyorum grep; ^kendisi düzenli ifadenin bir parçasıdır, bu yüzden kullanmak düzenli ifadelerin yorumlanmasını gerektirir. Bu alt dize eşleştirme kullanarak Önemsiz awk, perlya da her neyse:

awk -v search="$1" 'substr($0, 1, length(search)) == search { print }'

İçeren arama dizelerini işlemek için 123'ün cevabındaki\ numarayı kullanabilirsiniz :

search="$1" awk 'substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }'

Bu,\/
123

@ 123 gerçekten, bununla başa çıkmak için bir varyant ekledim.
Stephen Kitt

Hala gibi karmaşık dizeleri için başarısız olur \\\/\/\/\\\\/yani olarak görülüyor \\///\\/programda. Bildiğim kadarıyla önceden kaç tane kullanılacağını bilmiyorsanız, ters eğik çizgilerden awk'den kaçmanın bir yolu yoktur.
123

1
@ 123 teşekkürler, kaçış işlemlerinden kaçınmak için çevreye girme hilenizi uyarladım.
Stephen Kitt

Ben hala bu çözümü en çok seviyorum. Verimli (awk + etrafa zaman kaybetmeden), hızlı başlatma (awk + durumu ayarlamak için ek işlem gerekmez) standart araçlar kullanır ve oldukça özlüdür. Diğer tüm cevaplar bunlardan en azından bazılarından yoksundur. (Verimlilik burada güçlü bir noktadır, çünkü grep eşsiz hız ile bilinir.)
PSkocik

14

Yalnızca bir eşleşme bulunup bulunmadığını kontrol etmeniz gerekiyorsa, tüm giriş satırlarını istenen önek ( $1) uzunluğuna kadar kesin ve ardından sabit kalıp grep kullanın:

if cut -c 1-"${#1}" | grep -qF "$1"; then
    echo "found"
else
    echo "not found"
fi

Eşleşen hatların sayısını elde etmek de kolaydır:

cut -c 1-"${#1}" | grep -cF "$1"

Veya eşleşen tüm satırların satır numaraları (satır numaraları 1'den başlar):

cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1

Sen satır numaralarını yem olabilir headve taileşleştirme hatları tam metnini almak için, ama bu noktada sadece Python veya Ruby gibi modern bir komut dosyası dili ulaşmak daha kolaydır.

(Yukarıdaki örneklerde Posix grep ve cut varsayılmaktadır. Aranacak dosyanın standart girdiden geldiğini varsayarlar, ancak bunun yerine dosya adı alacak şekilde kolayca uyarlanabilirler.)

Düzenle: Desenin ( $1) sıfır uzunluklu bir dize olmadığından da emin olmalısınız . Aksi takdirde cutsöyleyemez values may not include zero. Ayrıca, Bash kullanıyorsanız, set -o pipefailhata çıkışlarını yakalamak için kullanın cut.


10

Ters eğik çizgilere saygı duyan perl kullanmanın bir yolu

v="$1" perl -ne 'print if index($_, $ENV{"v"} )==0' file

Bu, komut için ortam değişkenini v ayarlar, sonra değişkenin dizini 0 ise satırın başlangıcı ise yazdırır.

Ayrıca awk ile aynı şeyi yapabilirsiniz

v="$1" awk 'index($0, ENVIRON["v"])==1' file

7

İşte tüm-bash bir seçenek, metin işleme için bash tavsiye etmiyorum, ama işe yarıyor.

#!/usr/bin/env bash
# searches for $1 at the beginning of the line of its input

len=${#1}
while IFS= read -r line
do
  [[ "${line:0:len}" = "$1" ]] && printf "%s\n" "$line"
done

Komut dosyası len, girilen $ 1 parametresinin uzunluğunu hesaplar , ardından ilk satırların len$ 1 ile eşleşip eşleşmediğini görmek için her satırda parametre genişletmeyi kullanır . Öyleyse, çizgiyi yazdırır.


4

Eğer senin $1saf ASCII ve senin grepsahiptir -P(PCRE'yi etkinleştirmek için) seçeneğini, bunu yapabilirsiniz:

#!/bin/bash

line_start="$1"
line_start_raw=$(printf '%s' "$line_start" | od -v -t x1 -An)
line_start_hex=$(printf '\\x%s' $line_start_raw)
grep -P "^$line_start_hex"

Buradaki fikir grep -P, düzenli ifadelerin \xXXdeğişmez karakterleri belirtmesine izin vermesidir XX; bu karakterin onaltılık ASCII değeri. Karakter, aksi takdirde özel bir normal ifade karakteri olsa bile, kelimenin tam anlamıyla eşleştirilir.

odbeklenen satır başlangıcını, her biri \xprintf ile ön eklenmiş olan, daha sonra birbirine asılan onaltılık değerler listesine dönüştürmek için kullanılır . ^daha sonra gerekli normal ifadeyi oluşturmak için bu dizenin başına eklenir.


Eğer $1unicode ise, bu biraz daha zorlaşır, çünkü çıktı olarak 1: 1 karakterlerin onaltılık baytlara yazışması yoktur od.


3

Filtre olarak:

perl -ne 'BEGIN {$pat = shift} print if /^\Q$pat/' search-pattern

Bir veya daha fazla dosyada çalıştırın:

perl -ne 'BEGIN {$pat = shift} print if /^\Q$pat/' search-pattern file..

Perlre dokümanlarının “aktaran meta” bölümü açıklıyor:

Meta karakterlerden alıntı yapma

Perl ters bölü işareti meta gibi, alfanümerik olan \b, \w, \n. Diğer bazı normal ifade dillerinin aksine, alfasayısal olmayan ters eğik semboller yoktur. Bakışlar ister şey Böylece \\, \(, \), \[, \], \{, veya \}her zaman bir harf karakter değil, bir meta karakter olarak yorumlanır. Bu, bir zamanlar yaygın bir deyimde, bir desen için kullanmak istediğiniz bir dizedeki normal ifade metakarakterlerinin özel anlamlarını devre dışı bırakmak veya alıntılamak için kullanıldı. "Kelime" dışındaki tüm karakterleri alıntılamanız yeterlidir:

    $pattern =~ s/(\W)/\\$1/g;

( use localeAyarlanmışsa, bu geçerli yerel ayara bağlıdır.) Bugün, tüm metakarakterlerin bu gibi özel anlamlarını devre dışı bırakmak için quotemetaişlevi veya \Qmeta tırnak kaçış sırasını kullanmak daha yaygındır :

    /$unquoted\Q$quoted\E$unquoted/

Dikkat bu sen arasındaki değişmez ters eğik çizgi (o değil içeride interpolated değişkenler) koyarsanız \Qve \Eçift quotish ters eğik çizgi interpolasyon kafa karıştırıcı sonuçlara yol açabilir. Eğer değişmesi içinde ters eğik çizgi gerekiyorsa \Q...\E, danışmak perlop içinde “alıntı yapıları ayrıştırma Gory ayrıntıları” .

quotemetave \Qtam olarak quotemeta'da açıklanmaktadır .


3

Grep'iniz PCRE anlamına gelen -P seçeneğine sahipse , bunu yapabilirsiniz:

grep -P "^\Q$1\E"

Bu soruya bakın ve isterseniz ayrıntılar için PCRE belgesine bakın .


2

Kullanmadığınız bir karakter varsa, bunu satırın başlangıcını işaretlemek için kullanabilirsiniz. Örneğin, $'\a'(ASCII 007). Çirkin ama işe yarayacak:

{ echo 'this is a line to match'; echo 'but this is not'; } >file.txt

stuffing=$'\a'    # Guaranteed never to appear in your source text
required='this'   # What we want to match that beginning of a line

match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//")

if [[ -n "$match" ]]
then
    echo "Yay. We have a match: $match"
fi

Eşleşen satır (lar) a ihtiyacınız yoksa, izini bırakıp sedkullanabilirsiniz grep -qF. Ama awk(veya perl) ile çok daha kolay ...


0

Döngüsüz bir dosyaya bakmak istediğinizde şunları kullanabilirsiniz:
Dosyayı arama dizesi uzunluğunda kesin

  cut -c1-${#1} < file

Sabit dizeleri ve dönüş hattı numaralarını arayın

  grep -Fn "$1" <(cut -c1-${#1} < file)

Satır numaralarını aşağıdaki gibi bir şey için kullanın sed -n '3p;11p' file

  sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed 's/:.*/p;/' | tr -d '\n')" file

Bu satırları silmek istediğinizde şunu kullanın:

  sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed 's/:.*/d;/' | tr -d '\n')" file
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.