Wie kann ich eine Datei löschen, wenn sie mit <html> in bash beginnt?

7

Ich benötige einen Bash-Befehl, um die gesamte Datei zu löschen, wenn die Datei selbst mit beginnt <html>.

Ich bin mir nicht sicher, wie ich das am besten angehen soll ...

Kontext: Ich lade eine Reihe von Dateien über Curl-Anfragen herunter. Meistens funktionieren die Downloads und die Verarbeitung einwandfrei. In anderen Fällen führt die Download-Anfrage jedoch aus irgendeinem Grund zu einem 404. Wenn ich diese bekomme, beginnt der Inhalt der heruntergeladenen Datei mit einem HTML-Tag. Wenn der Rest meiner Verarbeitung auf diese Datei trifft, hängt sie. Daher möchte ich vor meiner anderen Verarbeitung einen Befehl ausführen, um jede der Dateien zu katzen und die Datei zu löschen, wenn sie dieses HTML-Tag hat.

Sei mein Freund
quelle
Sie möchten nach Dateien suchen, die mit <html>einer Datei beginnen oder diese löschen <html>?
Seth
Ja. Ich habe einen zusätzlichen Kommentar hinzugefügt
BeMy Friend
@ Seth Ich möchte keinen Titel bearbeiten, wenn ein Mod dies bereits getan hat, aber der Titel scheint mir falsch zu sein. Dateien werden auf die gleiche Weise gelöscht, unabhängig davon, womit sie beginnen. Die Frage ist, wie man Dateien identifiziert , die einer bestimmten Bedingung entsprechen, und nicht, wie man sie löscht.
user50849
1
Beachten Sie, dass bei vielen HTML-Dateien das Start-Tag mit einem vorangestellt ist <!doctype something>.
Kroltan
Ist ein Python-Skript akzeptabel? Es ist viel einfacher zu schreiben und zu lesen als Bash Magic.
Siyuan Ren

Antworten:

20

Um die Frage zu beantworten, die Sie dazu veranlasst hat, diese Frage zu stellen, und nicht die, die Sie tatsächlich gestellt haben:

curl kann Ihnen zusätzlich zum Herunterladen der Datei den Statuscode mitteilen. Sie müssen den Inhalt der Datei dafür nicht überprüfen. Ein Beispiel für die Überprüfung des Status ist

status=$(curl -w '%{http_code}' "${url}" -o "${file}")
test "${status}" -eq 200 || rm -- "${file}"

Die verschiedenen Optionen, mit denen Sie arbeiten können, -wsind im Handbuch dokumentiert. Abhängig von Ihren Anforderungen möchten Sie diese möglicherweise erweitern, um mehr Informationen auszugeben und zu analysieren, und / oder die Überprüfung des Statuscodes so ändern, dass mehr als nur 200 zulässig sind.

hvd
quelle
1
Es ist wichtig, die Datei in Anführungszeichen zu setzen, falls sie Leerzeichen oder Sonderzeichen enthält. $fileVerwenden Sie daher stattdessen entweder "$file"oder "${file}". Aus Sicherheitsgründen sollten Sie auch die URL entweder "$url"oder angeben "${url}".
Paddy Landau
@PaddyLandau Das lag daran, dass ich die URL und den Dateinamen ursprünglich fest codiert und kurz vor dem Posten meiner Antwort in Variablen geändert hatte. Danke, bearbeitet. Auch für die Sicherheit, rmsollte --vor dem Dateinamen. Einige Leute verwenden wirklich Dateien mit dem Namen -i.
DVD
12

Mit diesem Befehl find können Sie alle Dateien löschen, die nur das <html>Muster in der ersten Zeile enthalten:

find . -type f -exec sh -c 'sed q "$0" | grep -qP "^<html>$" && rm "$0"' {} \;
Sylvain Pineau
quelle
Was ist mit dem \;?
Shahbaz
1
@ Shahbaz \;ist erforderlich, um das Ende der -execAktion zu identifizieren
Sylvain Pineau
4
Dies funktioniert nicht (und ist zumindest theoretisch gefährlich), wenn einer der Dateinamen doppelte Anführungszeichen enthält. Die Verwendung -exec sh -c 'head -1 "$0" ...' {} \;ist zuverlässiger.
Dennis
@ Tennis vielen Dank für den Vorschlag, ich habe den Befehl behoben.
Sylvain Pineau
1
Ich bevorzuge es im Allgemeinen, Lösungen zu finden, aber in diesem Fall scheint es viel verwirrender und komplizierter zu sein als eine einfache for-Schleife.
Seth
8

Ich habe das gerade getestet, es funktioniert.

Führen Sie shoptzuerst aus, weil wir nicht analysieren möchtenls :

shopt -s nullglob  

Verwenden Sie dann eine einfache Bash- forSchleife, um Dateien zu finden, die mit beginnen, <html>und entfernen Sie sie:

for i in *; do if [ "$(head -n 1 "$i")" == '<html>' ]; then rm "$i"; fi; done  

Es wäre sicherer zu verwenden:

for i in *; do if [ "$(head -n 1 "$i")" == '<html>' ]; then rm -i "$i"; fi; done  

zu haben , rmzu fragen , bevor alle Dateien, nur für den Fall zu entfernen.

Beachten Sie, dass dies shoptnicht unbedingt erforderlich ist, aber verhindert, dass bestimmte Probleme auftreten, wenn das Verzeichnis leer ist oder eine Datei mit einem Sternchen im Namen vorhanden ist.

Seth
quelle
Perfekt, danke. Ich denke, ich hätte mir das selbst einfallen lassen sollen. Wahrscheinlich Zeit für eine Pause.
BeMy Friend
1

Nicht jede Automatisierungsaufgabe sollte mit Shell ausgeführt werden. Hier ist stattdessen ein Python-Skript

#!/usr/bin/env python
import os

def is_html_file(file_name):
    # Actually, try/except is better
    # But not very readable for someone not familiar with python
    if not os.path.isfile(file_name):
        return False
    with open(file_name, 'rb') as f:
        # A lot of HTML file starts with doctype
        # It is better to check that too
        return f.read(6) == '<html>'

def main():
    # Use os.walk if recursion is needed
    for fn in os.listdir('.'):
        if is_html_file(fn):
            print 'Removing', fn, '...'
            os.remove(fn)

main()

Vielleicht ist es ausführlicher als die entsprechenden Bash-Befehle, aber es ist

  1. Mehr lesbar
  2. Erweiterbarer
  3. Niemals durch Dateinamen mit Leerzeichen und Shell-Metazeichen vermasselt werden, egal wie nachlässig Sie sind.
Siyuan Ren
quelle