sed: Löschen einer Liste von Pfaden aus einem Dateisatz

363
Dave

Ich habe eine Datei namens common.txt, die eine Liste absoluter Pfade enthält. Zum Beispiel:

/etc /etc/group /var/log/syslog 

Ich habe auch eine Reihe von Dateien <hostname> .txt, die auch eine Liste absoluter Pfade enthalten. Hier ist ein Beispiel (nennen Sie es host1.txt ):

/root/.bashrc /var/log/syslog /etc/hosts /bin/true /etc /sbin/rtmon /etc/group 

Ich möchte jeden Pfad, der in common.txt angezeigt wird, aus jeder Datei im Dateisatz <Dateiname> .txt entfernen . Die Beispieldatei host1.txt würde also zu:

/root/.bashrc /etc/hosts /bin/true /sbin/rtmon 

Ich habe dazu das folgende Bash-Skript geschrieben:

#!/bin/bash  set -o nounset set -o errexit set -o pipefail  while read -r ONE_PATH do for ONE_FILE in host1.txt host2.txt host3.txt do sed -i '\:'"$ONE_PATH"':d' "$ONE_FILE" done done < common.txt 

Ich habe Schwierigkeiten, den sed-Befehl richtig zu machen. Was oben gezeigt wird, führt dazu, dass alle Dateien bearbeitet werden, wenn sie leer sind.

Wie kann ich das beheben, um mein Ziel zu erreichen?

0
Die Ausgabe von `grep -v -f common.txt somefile.txt` ist der Inhalt von` somefile.txt` ohne Zeilen, die eine Zeile in `common.txt` enthalten. xenoid vor 6 Jahren 1
Können Sie ein Beispiel für beide Dateien und das gewünschte Ergebnis liefern? Nur damit ich meine Antwort testen kann. Gerard H. Pille vor 6 Jahren 0
Ich habe das angeforderte Beispiel bereitgestellt, um den Thread für zukünftige Leser zu verbessern, aber ich hatte noch keine Gelegenheit, Ihre überarbeitete Lösung auszuprobieren. Dave vor 6 Jahren 0
Was ist die Ausgabe von `sed '\: ^ / etc $: d' host1.txt`? Wenn überhaupt. Daves Antwort unten hat einen Punkt. `common.txt` hat` / etc`, deshalb wird auch die Zeile `/ etc / hosts` aus host1.txt gelöscht.` sed` löscht ALLE Zeilen, die `/ etc` enthalten, entsprechend Ihrer Adresse. Fügen Sie Anker hinzu, um dies zu vermeiden. Paulo vor 6 Jahren 0

3 Antworten auf die Frage

1
Dave
#!/bin/bash  set -o nounset set -o errexit set -o pipefail  declare -r SCRIPT_DIR="$( cd "$( dirname "$" )" && pwd )" declare -r FILES_DIR=$  while read -r ONE_PATH do for ONE_FILE in $(find "$FILES_DIR" -maxdepth 1 -type f -print) do if [[ "$ONE_FILE" == *".swp" ]] || [[ "$ONE_FILE" == *"common.txt" ]]; then continue fi  sed -i '\|^'"$ONE_PATH"'$|d' "$ONE_FILE" done  echo "Done removing $ONE_PATH" done < "$SCRIPT_DIR"/../common.txt  exit 0 
0
BLiao

Darf ich eine Lösung vorschlagen, die sed nicht verwendet?

sort common.txt > common.txt.sorted for f in host1.txt host2.txt host3.txt ; do sort $f > $f.sorted diff common.txt.sorted $f.sorted | egrep '^>' | sed -e 's/^> //' > $f.output rm $f.sorted done 

Art sortiert Listen in alphabetischer Reihenfolge. diff findet die Unterschiede zwischen einer Datei und common.txt . egrep wählt Zeilen aus, die mit beginnen . Dies> sind Zeilen in host1.txt.sorted, jedoch nicht in common.txt.sorted . Zum Schluss entfernt sed das führende >(durch ein Leerzeichen gefolgtes Leerzeichen), das von diff hinzugefügt wird .

Die Ausgabeliste wird auch in alphabetischer Reihenfolge angezeigt.

-1
Gerard H. Pille

Zuerst sollte die Eingabe in umgekehrter Reihenfolge sein. Es ist sinnlos, / etc zu entfernen und dann nach / etc / group zu suchen. Dann überprüfen wir, ob in die Datei geschrieben werden kann (falls nicht übersprungen). Dann sollte ONE_PATH entkommen werden und Sed kann dann seine Arbeit verrichten.

sort -r common.txt \ | while read -r ONE_PATH do for ONE_FILE in host1.txt host2.txt host3.txt do if [ -w "$ONE_FILE" ] then # sed -i '\:'"$ONE_PATH"':d' "$ONE_FILE" ONE_PATH_ESC=$(echo "$ONE_PATH" | sed "s!/!\\\/!g") sed -i 's/^'"$ONE_PATH_ESC"'//' "$ONE_FILE" fi done done 

Mit den bereitgestellten Testdaten erhalten Sie:

$ pr -n host1.txt 1 /root/.bashrc 2 3 /hosts 4 /bin/true 5 6 /sbin/rtmon 7 

Es gibt 3 leere Zeilen.

Sie haben das nicht getestet, oder? Scott vor 6 Jahren 0
@Scott Jetzt habe ich. Gerard H. Pille vor 6 Jahren 0