Jak miałbym użyć sed, aby usunąć wszystkie wiersze w pliku tekstowym zawierającym określony ciąg?
Jak miałbym użyć sed, aby usunąć wszystkie wiersze w pliku tekstowym zawierającym określony ciąg?
Odpowiedzi:
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 sedem BSD:
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
sed '/pattern to match/d' ./infile > ./newfile
lub jeśli chcesz dokonać edycji w miejscu, możesz dodać -i
flagę do sed jak w sed -i '/pattern to match/d' ./infile
. Zauważ, że -i
flaga wymaga GNU sed i nie jest przenośna
sed -i.backup '/pattern to match/d' ./infile
) Dzięki temu wprowadziłem zmiany w miejscu.
sed
do plików, które nie są kontrolowane przez wersję.
sed -i '' '/pattern/d' ./infile
.
Istnieje wiele innych sposobów usuwania linii z określonym ciągiem znaków sed
:
awk '!/pattern/' file > temp && mv temp file
ruby -i.bak -ne 'print if not /test/' file
perl -ni.bak -e "print unless /pattern/" file
while read -r line
do
[[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file
grep -v "pattern" file > temp && mv temp file
I oczywiście sed
(wydruk odwrotny jest szybszy niż faktyczne usunięcie):
sed -n '/pattern/!p' file
sed
przykład mieć inny problem, to tylko greps! powinno być coś takiego sed -n -i '/pattern/!p' file
.
grep -v "pattern" file > temp; mv temp file
może to dotyczyć niektórych innych przykładów w zależności od wartości zwracanej.
seq -f %f 10000000 >foo.txt
. sed d: time sed -i '' '/6543210/d' foo.txt
prawdziwe 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txt
real 0m13.671s. (W przypadku mniejszych plików różnica jest większa.)
Możesz użyć sed, aby zamienić linie w pliku. Wydaje się jednak, że jest znacznie wolniejszy niż użycie grep dla odwrotności do drugiego pliku, a następnie przeniesienie drugiego pliku na oryginał.
na przykład
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 moim komputerze.
sed '/pattern/d' filename > filename2; mv filename2 filename
Łatwy sposób na zrobienie tego z GNU sed
:
sed --in-place '/some string here/d' yourfile
-r
opcję (lub -E
, w zależności od wersji). Umożliwia to korzystanie z regex metaznakami +
, ?
, {...}
i (...)
.
Możesz rozważyć użycie ex
(który jest standardowym edytorem uniksowym opartym na poleceniach):
ex +g/match/d -cwq file
gdzie:
+
wykonuje dane polecenie Ex ( man ex
), tak samo jak to, -c
które wykonuje wq
(zapisz i wyjdź)g/match/d
- Polecenie Ex do usuwania linii z danym match
, patrz: Moc gPowyższy przykład jest zgodną z POSIX metodą edycji na miejscu pliku zgodnie z tym postem w specyfikacji Unix.SE i POSIX dlaex
.
Różnica sed
polega na tym, że:
sed
to iterator S tream ED , a nie edytor plików. BashFAQ
Chyba że podoba Ci się nieobsługiwany kod, narzut I / O i inne złe skutki uboczne. Zasadniczo niektóre parametry (takie jak na miejscu / -i
) są niestandardowymi rozszerzeniami FreeBSD i mogą nie być dostępne w innych systemach operacyjnych.
man ex
daje mi mężczyznę vim
, wydaje się, ex
jest częścią vim ... gdybym rozumieć prawo to oznacza dla składni wzór match
jest vimregex.com która jest podobna, ale różni się od POSIX PCRE i smaków?
:g
to polecenie zgodne z POSIX, z pewnymi niewielkimi różnicami . Zakładam, że PCRE było na nim oparte.
Walczyłem z tym na Macu. Dodatkowo musiałem to zrobić, używając zmiennej zamiany.
Więc użyłem:
sed -i '' "/$pattern/d" $file
gdzie $file
jest plik, w którym konieczne jest usunięcie, i $pattern
wzór, który należy dopasować do usunięcia.
Wybrałem ''
z tego komentarza .
Należy 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.
sed
wymaga parametru po -i
, więc jeśli nie chcesz kopii zapasowej, nadal musisz dodać pusty ciąg:-i ''
sed -i "/$pattern/d" $file
. Dziękuję za Twoją odpowiedź.
Zrobiłem mały test porównawczy z plikiem, który zawiera około 345 000 linii. Sposób z grep
wydaje się być około 15 razy szybszy niż sed
metoda w tym przypadku.
Próbowałem zarówno z, jak i bez ustawienia LC_ALL = C, wydaje się, że nie zmienia to znacząco czasów. Wyszukiwany ciąg (CDGA_00004.pdbqt.gz.tar) znajduje się gdzieś pośrodku pliku.
Oto polecenia i czasy:
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
Możesz także użyć tego:
grep -v 'pattern' filename
Tutaj -v
wydrukuje się tylko inny wzór niż twój (co oznacza dopasowanie odwrócone).
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
Pierwsze polecenie edytuje plik (i) w miejscu (-i).
Drugie polecenie robi to samo, ale zachowuje kopię lub kopię zapasową oryginalnych plików, dodając .bk do nazw plików (.bk można zmienić na dowolne).
Na wypadek, gdyby ktoś chciał to zrobić dla dokładnego dopasowania ciągów, możesz użyć -w
flagi w grep - w dla całości. To znaczy, na przykład, jeśli chcesz usunąć linie o numerze 11, ale zachowaj linie o numerze 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 -f
flagą, jeśli chcesz wykluczyć kilka dokładnych wzorów jednocześnie. Jeśli „czarna lista” to plik z kilkoma wzorami w każdej linii, który chcesz usunąć z „pliku”:
grep -w -v -f blacklist file
-w, --word-regexp Select only those lines containing matches that form whole words.
vs.-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
aby wyświetlić traktowany tekst w konsoli
cat filename | sed '/text to remove/d'
aby zapisać traktowany tekst w pliku
cat filename | sed '/text to remove/d' > newfile
aby dołączyć przetworzone informacje tekstowe do istniejącego pliku
cat filename | sed '/text to remove/d' >> newfile
aby leczyć 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
pokaże tekst kawałkami jednej strony na raz.
Można używać starych dobrych ed
edytować plik w podobny sposób do odpowiedzi , które wykorzystuje ex
. Dużą różnicą w tym przypadku jest to, że ed
przyjmuje polecenia za pomocą standardowego wejścia, a nie argumentów wiersza poleceń, jak ex
można. Kiedy używasz go w skrypcie, zwykłym sposobem na przystosowanie się do tego jest użycie printf
poleceń do niego:
printf "%s\n" "g/pattern/d" w | ed -s filename
lub z heredoc:
ed -s filename <<EOF
g/pattern/d
w
EOF