Jak usunąć z pliku tekstowego wszystkie linie zawierające określony ciąg znaków?

Jak użyć sed, aby usunąć wszystkie linie w pliku tekstowym, które zawierają określony ciąg znaków?

Author: ivanleoncz, 2011-03-23

18 answers

Aby usunąć linię I wydrukować wyjście na standardowe wyjście:

sed '/pattern to match/d' ./infile

Aby bezpośrednio zmodyfikować plik – nie działa z BSD sed:

sed -i '/pattern to match/d' ./infile

To samo, ale dla BSD sed – Mac OS X i FreeBSD)-nie działa z GNU sed:

sed -i '' '/pattern to match/d' ./infile

Aby bezpośrednio zmodyfikować plik – i utworzyć kopię zapasową) - działa z BSD i GNU sed:

sed -i.bak '/pattern to match/d' ./infile
 2984
Author: SiegeX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-27 09:57:09

Oprócz sed istnieje wiele innych sposobów usuwania linii z określonym ciągiem znaków:

AWK

awk '!/pattern/' file > temp && mv temp file

Ruby (1.9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (bash 3.2 i nowsze)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

I oczywiście sed (drukowanie odwrotności jest szybsze niż rzeczywiste usunięcie):

sed -n '/pattern/!p' file
 661
Author: kurumi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-15 22:06:06

Możesz użyć sed, aby zastąpić wiersze w pliku. Jednak wydaje się, że jest to znacznie wolniejsze niż użycie grepa do odwrotnej zmiany do drugiego pliku, a następnie przeniesienie drugiego pliku nad oryginał.

Np.

sed -i '/pattern/d' filename      

Lub

grep -v "pattern" filename > filename2; mv filename2 filename

Pierwsze polecenie i tak trwa 3 razy dłużej na mojej maszynie.

 267
Author: slashdottir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-19 15:07:10

Prosty sposób na to, z GNU sed:

sed --in-place '/some string here/d' yourfile
 84
Author: Kevin Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-11 23:50:54

Możesz rozważyć użycie ex (który jest standardowym uniksowym edytorem opartym na poleceniach):

ex +g/match/d -cwq file

Gdzie:

  • + wykonuje polecenie Ex (man ex), tak samo jak -c które wykonuje wq (write and quit)
  • g/match/d - Ex komenda do usuwania linii o podanym match, patrz: moc g

Powyższy przykład jest zgodną z POSIX metodą edycji pliku w miejscu, zgodnie z poniższym postem w Unix.SE i Specyfikacja POSIX na ex.


Różnica z sed jest taka, że:

sed jest S tream ED itor, a nie edytor plików.BashFAQ

Chyba, że lubisz kod nieportable, I / O overhead i inne złe skutki uboczne. Tak więc w zasadzie niektóre parametry (takie jak in-place/-i) są niestandardowymi rozszerzeniami FreeBSD i mogą nie być dostępne na innych systemach operacyjnych.

 43
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-15 22:08:57

Zmagałem się z tym na Macu. Poza tym musiałem to zrobić za pomocą wymiany zmiennych.

Więc użyłem:

sed -i '' "/$pattern/d" $file

Gdzie $file jest plikiem, w którym potrzebne jest usunięcie, a $pattern jest wzorcem, który należy dopasować do usunięcia.

Wybrałem '' z tego komentarza.

Należy tutaj zwrócić uwagę na użycie podwójnych cudzysłowów w "/$pattern/d". Zmienna nie będzie działać, gdy użyjemy pojedynczych cudzysłowów.

 22
Author: Aniket Sinha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-15 22:15:45

Możesz również użyć tego:

 grep -v 'pattern' filename

Tutaj -v wydrukuje tylko inny wzór niż twój wzór (co oznacza odwrócenie dopasowania).

 18
Author: Bhuvanesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-15 22:07:13

Zrobiłem mały benchmark z plikiem, który zawiera około 345 000 linii. Sposób z grep wydaje się być około 15 razy szybszy niż metoda sed w tym przypadku.

Próbowałem zarówno z ustawieniem LC_ALL=C, jak i bez niego, nie zmienia to znacząco czasu. Szukany ciąg (CDGA_00004.pdbqt.gz.tar) jest gdzieś w środku pliku.

Oto komendy i timingi:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s
 15
Author: Jadzia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-19 12:45:18

Aby uzyskać wynik inplace like z grep możesz to zrobić:

echo "$(grep -v "pattern" filename)" >filename
 13
Author: Jahid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-13 19:24:59
 9
Author: Oleg Mazko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-20 13:28:37
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Pierwsze polecenie edytuje plik(y) w miejscu (-i).

Drugie polecenie robi to samo, ale zachowuje kopię lub kopię zapasową oryginalnych plików przez dodanie .bk do nazw plików (.bk można zmienić na cokolwiek).

 4
Author: Kjetil S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-08 12:07:39

echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt

 2
Author: Shizzmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-16 23:51:31

Na wypadek, gdyby ktoś chciał to zrobić dla dokładnych dopasowań łańcuchów, możesz użyć znacznika -w w grep-w dla całości. Oznacza to, że na przykład, jeśli chcesz usunąć linie z numerem 11, ale zachować linie z numerem 111:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

Działa również z flagą -f, Jeśli chcesz wykluczyć kilka dokładnych wzorców naraz. Jeśli "czarna lista" jest plikiem z kilkoma wzorami w każdej linii, którą chcesz usunąć z"pliku":

grep -w -v -f blacklist file
 2
Author: FatihSarigol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-15 22:18:52
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
 1
Author: Andrey Izman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-29 16:45:24

Można również usunąć zakres linii w pliku. Na przykład, aby usunąć procedury przechowywane w pliku SQL.

sed '/CREATE PROCEDURE.*/,/END ;/d' sqllines.sql

Spowoduje usunięcie wszystkich linii pomiędzy procedurą CREATE I END ;.

Wyczyściłem wiele plików sql za pomocą tego polecenia sed.

 1
Author: GordyCA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-02 01:49:27

Aby pokazać traktowany tekst w konsoli

cat filename | sed '/text to remove/d' 

Aby zapisać traktowany tekst do pliku

cat filename | sed '/text to remove/d' > newfile

Aby dodać informacje tekstowe do istniejącego pliku

cat filename | sed '/text to remove/d' >> newfile

Aby potraktować już przetworzony tekst, w tym przypadku usuń więcej wierszy tego, co zostało usunięte

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

| more wyświetli tekst w kawałkach po jednej stronie na raz.

 0
Author: nassim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-27 20:19:32

Możesz użyć starego, dobrego ed, aby edytować plik w sposób podobny do odpowiedzi , która używa ex. Duża różnica w tym przypadku polega na tym, że ed pobiera swoje polecenia poprzez standardowe wejście, a nie jako argumenty linii poleceń, jak ex can. W przypadku użycia go w skrypcie, zwyczajowym sposobem na rozwiązanie tego problemu jest użycie printf do przesyłania komend do niego:

printf "%s\n" "g/pattern/d" w | ed -s filename

Lub z heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF
 0
Author: Shawn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-19 14:21:01

Co ciekawe, przyjęta odpowiedź nie odpowiada bezpośrednio na pytanie. Pytanie pyta o użycie sed do zastąpienia string, ale odpowiedź wydaje się zakładać wiedzę o tym, jak przekształcić dowolny łańcuch w regex.

Wiele bibliotek języka programowania posiada funkcję do wykonywania takiej transformacji, np.

python: re.escape(STRING)
ruby: Regexp.escape(STRING)
java:  Pattern.quote(STRING)

Ale jak to zrobić w wierszu poleceń?

Ponieważ jest to pytanie zorientowane na sed, jednym z podejść byłoby użycie sed:

sed 's/\([\[/({.*+^$?]\)/\\\1/g'

Więc mając dowolny łańcuch $STRING możemy napisać coś w stylu:

re=$(sed 's/\([\[({.*+^$?]\)/\\\1/g' <<< "$STRING")
sed "/$re/d" FILE

Lub jako jednoliterowy:

 sed "/$(sed 's/\([\[/({.*+^$?]\)/\\\1/g' <<< "$STRING")/d" 

Z wariacjami opisanymi w innym miejscu na tej stronie.

 0
Author: peak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-23 01:47:33