45 Stimmen

Interpretation als feste Zeichenkette/Literal und nicht als Regex mit sed

Para grep gibt es eine Option für feste Zeichenfolgen, -F ( fgrep ), um die Regex-Interpretation des Suchstrings zu deaktivieren. Gibt es eine ähnliche Möglichkeit für sed ? Ich konnte im Handbuch nichts finden. Eine Empfehlung für ein anderes Gnu/Linux-Tool wäre auch gut.

Ich benutze sed für die Funktion Suchen und Ersetzen: sed -i "s/abc/def/g"

11voto

dannysauer Punkte 3681

Müssen Sie die sed ? Wenn Sie ein Bash-Skript schreiben, können Sie Folgendes tun

#!/bin/bash

pattern='abc'
replace='def'
file=/path/to/file
tmpfile="${TMPDIR:-/tmp}/$( basename "$file" ).$$"

while read -r line
do
  echo "${line//$pattern/$replace}"
done < "$file" > "$tmpfile" && mv "$tmpfile" "$file"

Mit einer älteren Bourne-Shell (z. B. ksh88 oder POSIX sh) haben Sie möglicherweise nicht diese Möglichkeiten ${var/pattern/replace} Struktur, aber Sie haben ${var#pattern} y ${var%pattern} mit dem die Zeichenkette aufgespalten und wieder zusammengesetzt werden kann. Wenn Sie das tun müssen, müssen Sie viel mehr Code eingeben - aber es ist wirklich nicht so schlimm.

Wenn Sie nicht schon in einem Shell-Skript sind, können Sie ganz einfach die Parameter pattern, replace und filename angeben und dann einfach das hier aufrufen :)

PS: Die ${TMPDIR:-/tmp} Struktur verwendet $TMPDIR wenn diese in Ihrer Umgebung gesetzt ist, oder verwendet /tmp, wenn die Variable nicht gesetzt ist. Ich hänge gerne die PID des aktuellen Prozesses an das Ende des Dateinamens an, in der Hoffnung, dass es dann etwas eindeutiger ist. Sie sollten wahrscheinlich mktemp oder ähnliches in der "realen Welt", aber für ein kurzes Beispiel ist das in Ordnung, und die mktemp binär ist nicht immer verfügbar.

6voto

Kim Burgaard Punkte 3478

Option 1) Escape regexp Zeichen. z.B. sed 's/\$0\.0/0/g' ersetzt alle Vorkommen von $0,0 durch 0.

Option 2) Verwendung perl -p -e in Verbindung mit quotemeta. z.B. perl -p -e 's/\\./,/gi' ersetzt alle Vorkommen von . con , .

Sie können Option 2 in Skripten wie diesem verwenden:

SEARCH="C++"
REPLACE="C#"
cat $FILELIST | perl -p -e "s/\\Q$SEARCH\\E/$REPLACE/g" > $NEWLIST

4voto

Hubro Punkte 52122

Wenn Sie nichts gegen Ruby oder lange Warteschlangen haben, können Sie dies nutzen:

alias replace='ruby -e "File.write(ARGV[0], File.read(ARGV[0]).gsub(ARGV[1]) { ARGV[2] })"'

replace test3.txt abc def

Dies lädt die gesamte Datei in den Speicher, führt die Ersetzungen durch und speichert sie wieder auf der Festplatte. Sollte wahrscheinlich nicht für große Dateien verwendet werden.

4voto

Bastian Bittorf Punkte 407

Wenn Sie no Wenn Sie sich von Ihrer Schnur befreien wollen, können Sie Ihr Ziel in 2 Schritten erreichen:

  1. fgrep die Zeile (mit der Zeilennummer), die Sie ersetzen möchten, und
  2. anschließend verwenden sed um diese Zeile zu ersetzen.

z.B.

#/bin/sh
PATTERN='foo*[)*abc'    # we need it literal
LINENUMBER="$( fgrep -n "$PATTERN" "$FILE" | cut -d':' -f1 )"

NEWSTRING='my new string'
sed -i "${LINENUMBER}s/.*/$NEWSTRING/" "$FILE"

0voto

Grisha Levit Punkte 7669

Sie können dies in zwei Zeilen Bash-Code tun, wenn Sie damit einverstanden sind, die gesamte Datei in den Speicher zu lesen. Dies ist recht flexibel - das Muster und die Ersetzung können Zeilenumbrüche enthalten, um bei Bedarf zeilenübergreifend zu sein. Außerdem bleibt ein nachfolgender Zeilenumbruch oder das Fehlen eines solchen erhalten, was eine einfache Schleife mit read nicht.

mapfile -d '' < file
printf '%s' "${MAPFILE//"$pat"/"$rep"}" > file

Der Vollständigkeit halber: Wenn die Datei Null-Bytes enthalten kann ( \0 ), müssen wir den obigen Satz erweitern, und es wird

mapfile -d '' < <(cat file; printf '\0')
last=${MAPFILE[-1]}; unset "MAPFILE[-1]"
printf '%s\0' "${MAPFILE[@]//"$pat"/"$rep"}" > file
printf '%s' "${last//"$pat"/"$rep"}" >> file

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X