Jak znaleźć linie pasujące do wzoru i usunąć je?

14

W pliku z dużą ilością linii chcę usunąć linie zaczynające się od HERE IT IS.

Jak mogę to zrobić przy użyciu tylko narzędzi wiersza polecenia?

micgeronimo
źródło
2
Chociaż trochę niekonwencjonalne, możesz użyć vimtakiego vim '+g/^HERE IT IS/d' +wq test.txt
:;
@Doorknob, dziękuję za zwrócenie na to uwagi. Właściwie to jestem na najlepszej drodze do używania vima
micgeronimo,

Odpowiedzi:

29

Spróbuj sed:

sed -i '/^HERE IT IS/d' <file>

OSTRZEŻENIE: Lepiej zrobić kopię zapasową, używając -iprzełącznika sed:

sed -i.bak '/^HERE IT IS/d' <file>

Oryginalny plik pozostanie taki, jak <file>.bakzmodyfikowany plik <file>.

heemayl
źródło
Jak mogę wstawić znak nowej linii po dopasowanym ciągu i napisać w nowej linii?
micgeronimo,
2
sed -i 's/^HERE IT IS/HERE IT IS\n/' <file>
heemayl
1
@micgeronimo: chętnie pomoże. Proszę sprawdzić moje zmiany.
heemayl
6
@micgeronimo spróbuj zadać pytanie, na które naprawdę chcesz odpowiedzieć w swoim pierwotnym pytaniu (pamiętaj, że możesz je edytować), a nie poprzez komentarze, które mogą zostać usunięte / usunięte. Możesz użyć sed '/^HERE IT IS/G' file.
steeldriver
1
Korzystanie z Sed jest bardzo profesjonalne.
LakshyaAg
18

Oprócz bardzo dobrych grepi otrzymanych sedodpowiedzi, oto kilka innych narzędzi, które mogą zrobić to samo:

  • Kilka sposobów Perla:

    perl -ne '/^HERE IT IS/ || print' file > newfile
    perl -ne 'print if !/^HERE IT IS/' file > newfile
    perl -ne 'print unless /^HERE IT IS/' file > newfile
    

    Możesz dodać -iprzełącznik do dowolnego z przykładów, aby edytować plik w miejscu:

    perl -i.bak -ne '/^HERE IT IS/ || print' file        
    
  • (gapić się

    awk '!/^HERE IT IS/' file > newfile
    

    Nowsze wersje (4.1.1 i nowsze) GNU awk(domyślnie awkw Linuksie) mogą również edytować plik w miejscu:

    gawk -i inplace  '!/^HERE IT IS/' file
    
  • Shell ( bash, zsh, ksh, prawdopodobnie inne). Jest to trochę głupie, można to zrobić, ale inne narzędzia są lepsze.

    while IFS= read -r line; do 
      [[ $line =~ ^"HERE IT IS" ]] || printf "%s\n" "$line"
    done < file > newfile
    
terdon
źródło
1
Po prostu się popisujesz! ;-) (ale masz opinię pozytywną, ponieważ jest mądra i wiele się nauczyłam, a ta bashsprawiła, że ​​mnie LOL)
Fabby
bash, którego należy użyć printf "%s\n" "$line": cytując $ line, aby zachować białe spacje i uniknąć niektórych problemów z echami (interpretacja specjalnych znaków itp.). i unika potrzeby dodawania --.
Olivier Dulac
@OlivierDulac wystarczy. Nie chciałem komplikować sprawy z marginesami, ale odkąd Cuanglm dodał IFS=i -rrównie dobrze mogę zrobić wszystko, aby był solidny.
terdon
@terdon: to wszystko na lepsze ^^ (i już dawałem +1, ponieważ jest to bardzo pouczające dla początkujących)
Olivier Dulac
2
@OlivierDulac Mogę zapewnić, że gdybym pisał na Unixie i Linuksie, użyłbym printf, IFS =, -r i cytowania :). Często upraszczam rzeczy dla odbiorców z AU, którzy często nie czują się komfortowo w wierszu poleceń.
terdon
13

Użyłbym grepfiltrować je. Na przykład :

grep -v "^HERE IT IS" infile > outfile

Następnie przenieś outfile z powrotem do infile.

Ben Hills
źródło
Sprytne myślenie
Anwar
5

sed to zdecydowanie najlepsza droga.

Ta niewielka modyfikacja polecenia @ heemayl spowodowała usunięcie linii bez względu na to, czy we wzorcu użyto tego samego przypadku, czy nie, ze względu na I w odwołaniu do wzorca.

sed -i '/HERE IT IS/Id' <file>

Jeśli masz kilka plików w katalogu, w którym chcesz to zrobić, możesz połączyć to z find w ten sposób.

find . -maxdepth 1 -type f -exec sed -i.bak '/HERE IT IS/Id' {} +

Opcja maxdepth oznacza, że ​​nie będzie się to powtarzać w katalogach.

Arroniczny
źródło
4

Inna opcja Pythona:

#!/usr/bin/env python3
[print(l, end = "") for l in open(f).readlines() if not l.startswith("HERE IT IS")]

Gdzie f jest ścieżką do pliku między cudzysłowami.

Jacob Vlijm
źródło
4

Grep

grep -P '^(?!HERE IT IS)' file

(?!HERE IT IS)negatywne stwierdzenie wyprzedzające, które powoduje, że silnik wyrażenia regularnego dopasowuje całą granicę początkową linii ( która zwykle jest dopasowywana^ ) tylko wtedy, gdy nie następuje po niej ciągHERE IT IS

pyton

#!/usr/bin/python3
import sys
fil = sys.argv[1]
with open(fil) as f:
    for line in f:
        if not line.startswith('HERE IT IS'):
            print(line, end="")

Zapisz skrypt w pliku, powiedz, script.pya następnie uruchom go za pomocą poniższego polecenia na terminalu.

python3 script.py infile
Avinash Raj
źródło
możesz tam użyć wyrażenia regularnego [print(l, end = "") for l in open(fil).readlines() if not re.match("HERE IT IS", l)], ale nie jest to o wiele bardziej wydajne niż startswith. Zastanawiałem się, jak [print(l, end = "") for l in open(f).readlines() if not l.startswith("HERE IT IS")]nie będzie generować wyników na liście.
Avinash Raj,
Za pierwszym razem, gdy na niego wpadłem, wyglądało to dziwnie. Generuje polecenie drukowania (lub dowolną akcję, którą chcesz z nim wykonać) dla wszystkich elementów na zdefiniowanej liście.
Jacob Vlijm
Odzyskiwanie go, dla zabawy :)
Jacob Vlijm,
1

Możesz używać Vima w trybie Ex:

ex -sc 'g/^HERE IT IS/d' -cx file
  1. g globalne wyszukiwanie

  2. d usunąć

  3. x Zapisz i zamknij

Steven Penny
źródło