it-swarm.com.de

Linux-Befehl: Wie kann ich nur Textdateien finden?

Nach einigen Suchanfragen bei Google komme ich auf:

find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text

dies ist sehr unhandlich und gibt nicht benötigte Texte aus, z. Irgendwelche besseren Lösungen? Ich habe viele Bilder und andere Binärdateien im selben Ordner mit vielen Textdateien, die ich durchsuchen muss.

82
datasn.io

Ich weiß, dass dies ein alter Thread ist, aber ich bin darüber gestolpert und dachte, ich würde meine Methode teilen, die ich als sehr schnelle Möglichkeit gefunden habe, find zu verwenden, um nur nicht-binäre Dateien zu finden:

find . -type f -exec grep -Iq . {} \; -print

Die -I-Option für grep weist an, Binärdateien sofort zu ignorieren. Die .-Option zusammen mit dem -q sorgt dafür, dass die Textdateien sofort mit den Textdateien übereinstimmen. Dies geschieht sehr schnell. Sie können den -print in einen -print0 umleiten, um in einen xargs -0 oder etwas weiterzuleiten, wenn Sie sich um Leerzeichen sorgen (danke für den Tipp, @ lucas.werkmeister!)

Der erste Punkt ist nur für bestimmte BSD-Versionen von find erforderlich, wie z. B. unter OS X, aber es schadet nichts, wenn Sie ihn ständig dabei haben, wenn Sie dies in einen Alias ​​oder etwas einfügen möchten.

EDIT: Wie @ruslan richtig angegeben hat, kann der -and weggelassen werden, da er impliziert ist.

146
crudcore

Warum ist es unhandlich? Wenn Sie sie häufig verwenden müssen und nicht jedes Mal eingeben möchten, definieren Sie einfach eine Bash-Funktion dafür:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text
}

legen Sie es in Ihren .bashrc und dann führen Sie einfach aus:

findTextInAsciiFiles your_folder "needle text"

wann immer du willst.


EDITum die Bearbeitung von OP anzuzeigen:

wenn Sie die Mime-Informationen ausschneiden möchten, können Sie der Pipeline einfach eine weitere Stufe hinzufügen, die die Mime-Informationen herausfiltert. Dies sollte den Trick erfüllen, indem nur das genommen wird, was vor :: cut -d':' -f1 liegt:

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}
10
peoro

Basierend auf dieser SO Frage :

grep -rIl "needle text" my_folder

9
crayzeewulf
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

Dies ist leider nicht platzsparend. Wenn Sie dies in das bash-Skript einfügen, wird es etwas einfacher. 

Dies ist Platz sicher:

#!/bin/bash
#if [ ! "$1" ] ; then
    echo "Usage: $0 <search>";
    exit
fi

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "$1" "%"

Wie wäre es damit:

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable'

Wenn Sie die Dateinamen ohne die Dateitypen haben möchten, fügen Sie einfach einen abschließenden sed-Filter hinzu.

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

Sie können nicht benötigte Dateitypen herausfiltern, indem Sie dem letzten grep-Befehl weitere -e 'type'-Optionen hinzufügen.

BEARBEITEN:

Wenn Ihre xargs-Version die -d-Option unterstützt, werden die obigen Befehle einfacher:

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'
2
thkala

Ich habe zwei Probleme mit der Antwort von histumness:

  • Es werden nur Textdateien aufgelistet. Es durchsucht sie nicht tatsächlich als Angefordert. Um tatsächlich zu suchen, verwenden Sie

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • Für jede Datei wird ein Grep-Prozess erzeugt, der sehr langsam ist. Eine bessere Lösung ist dann

    find . -type f -print0 | xargs -0 grep -IZl . | xargs -0 grep "needle text"
    

    oder einfach

    find . -type f -print0 | xargs -0 grep -I "needle text"
    

    Dies dauert nur 0,2 Sekunden im Vergleich zu 4 Sekunden für die Lösung oberhalb (2,5 GB Daten/7700 Dateien), d. H. 20x schneller.

Auch niemand zitiert ag, der Silver Searcher oder ack-grep ¸als Alternativen. Wenn eine davon verfügbar ist, sind sie viel bessere Alternativen:

ag -t "needle text"    # Much faster than ack
ack -t "needle text"   # or ack-grep

Als letzte Bemerkung ist vor Fehlalarmen (Binärdateien als Textdateien) zu schützen. Ich hatte bereits ein falsches positives Ergebnis bei der Verwendung von grep/ag/ack. Listen Sie also die übereinstimmenden Dateien auf, bevor Sie die Dateien bearbeiten.

2
fuujuhi

So habe ich es gemacht ...

1 Erstellen Sie ein kleines Skript, um zu testen, ob es sich bei einer Datei um Klartext handelt istext:

#!/bin/bash
[[ "$(file -bi $1)" == *"file"* ]]

2 Verwenden Sie find wie zuvor

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;
2
Robert

Eine andere Möglichkeit, dies zu tun: 

# find . |xargs file {} \; |grep "ASCII text"

Wenn Sie auch leere Dateien wünschen: 

#  find . |xargs file {} \; |egrep "ASCII text|empty"
1
The IT Guy

Obwohl es sich um eine alte Frage handelt, wird diese Information meiner Meinung nach die Qualität der Antworten verbessern.

Wenn ich Dateien mit dem ausführbaren Bit set ignoriere, benutze ich einfach diesen Befehl:

find . ! -perm -111

Um zu verhindern, dass es rekursiv in andere Verzeichnisse eintritt:

find . -maxdepth 1 ! -perm -111

Es ist nicht notwendig, dass pipes viele Befehle mischt, nur den leistungsstarken einfachen find -Befehl.

  • Haftungsausschluss: Es ist nicht genau was OP gefragt hat, weil nicht geprüft wird, ob die Datei binary ist oder nicht. Es filtert beispielsweise bash script -Dateien heraus, die text selbst sind, aber das ausführbare Bit gesetzt haben .

Ich hoffe, das ist für jeden nützlich.

1
Dr Beco

Ich mache es so: 1) Da es zu viele Dateien (~ 30k) für die Suche gibt, generiere ich täglich die Liste der Textdateien für die Verwendung über Crontab mit dem folgenden Befehl:

find /to/src/folder -type f -exec file {} \; | grep text | cut -d: -f1 > ~/.src_list &

2) Erstellen Sie eine Funktion in .bashrc:

findex() {
    cat ~/.src_list | xargs grep "$*" 2>/dev/null
}

Dann kann ich den folgenden Befehl verwenden, um die Suche durchzuführen:

findex "needle text"

HTH :)

0
Frank Fang

Hier ist eine vereinfachte Version mit erweiterten Erklärungen für Anfänger wie mich, die versuchen zu lernen, wie mehrere Befehle in einer Zeile stehen.

Wenn Sie das Problem schrittweise ausschreiben würden, würde es so aussehen:

// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename

Um dies zu erreichen, können wir drei UNIX-Befehle verwenden: find, file und grep

find überprüft jede Datei im Verzeichnis. 

file gibt uns den Dateityp. In unserem Fall suchen wir nach einer Rückgabe von 'ASCII-Text'.

grep sucht in der Ausgabe von file nach dem Schlüsselwort 'ASCII'.

Wie können wir diese also in einer Zeile zusammenfassen? Es gibt mehrere Möglichkeiten, dies zu tun, aber ich finde, dass es am sinnvollsten ist, es in der Reihenfolge unseres Pseudo-Codes zu machen (insbesondere für einen Anfänger wie mich). 

find ./ -exec file {} ";" | grep 'ASCII'

Sieht kompliziert aus, aber nicht schlecht, wenn wir es zusammenbrechen:

find ./ = Durchsuchen Sie jede Datei in diesem Verzeichnis. Der Befehl find gibt den Dateinamen einer Datei aus, die mit dem 'Ausdruck' übereinstimmt, oder was immer hinter dem Pfad steht. In unserem Fall handelt es sich um das aktuelle Verzeichnis oder ./.

Das Wichtigste zu verstehen ist, dass alles nach dem ersten Bit entweder als wahr oder falsch bewertet wird. Bei True wird der Dateiname ausgedruckt. Wenn nicht, geht der Befehl weiter. 

-exec = Dieses Flag ist eine Option innerhalb des Suchbefehls, mit der wir das Ergebnis eines anderen Befehls als Suchausdruck verwenden können. Es ist, als würde man eine Funktion innerhalb einer Funktion aufrufen.

file {} = Der Befehl, der innerhalb von find aufgerufen wird. Der Befehl file gibt eine Zeichenfolge zurück, die den Dateityp einer Datei angibt. Normalerweise würde es so aussehen: file mytextfile.txt. In unserem Fall möchten wir, dass die Datei verwendet wird, die mit dem Befehl find betrachtet wird. Daher setzen wir die geschweiften Klammern {} als leere Variable oder Parameter. Mit anderen Worten, wir fordern nur, dass das System für jede Datei im Verzeichnis einen String ausgibt. 

";" = wird von find benötigt und ist das Interpunktionszeichen am Ende unseres -exec-Befehls. Weitere Informationen finden Sie im Handbuch für 'find', wenn Sie man find benötigen.

| grep 'ASCII' = | ist eine Pipe. Pipe nimmt die Ausgabe von dem, was sich auf der linken Seite befindet, und verwendet es als Eingabe für das, was sich auf der rechten Seite befindet. Es nimmt die Ausgabe des Befehls find (eine Zeichenfolge, die den Dateityp einer einzelnen Datei darstellt) und testet sie, um festzustellen, ob sie die Zeichenfolge 'ASCII' enthält. Wenn dies der Fall ist, wird true zurückgegeben.

JETZT gibt der Ausdruck rechts von find ./ den Wert true zurück, wenn der Befehl grep den Wert true zurückgibt. Voila. 

0
mepler

Wenn Sie daran interessiert sind, einen Dateityp anhand seiner magischen Bytes mit dem awesome file-Dienstprogramm in Kombination mit der Kraft von find zu finden, kann dies nützlich sein:

$ # Let's make some test files
$ mkdir ASCII-Finder
$ cd ASCII-Finder
$ dd if=/dev/urandom of=binary.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.009023 s, 116 MB/s
$ file binary.file
binary.file: data
$ echo 123 > text.txt
$ # Let the magic begin
$ find -type f -print0 | \
    xargs -0 -I @@ bash -c 'file "[email protected]" | grep ASCII &>/dev/null && echo "file is ASCII: [email protected]"' -- @@

Ausgabe:

file is ASCII: ./text.txt

Legende: $ ist die interaktive Shell-Eingabeaufforderung, an der wir unsere Befehle eingeben

Sie können den Part nach && ändern, um ein anderes Skript aufzurufen oder auch andere Inline-Funktionen auszuführen, d. H. Wenn diese Datei einen angegebenen String enthält, können Sie die gesamte Datei katalogisieren oder darin nach einem sekundären String suchen.

Erklärung:

  • find Elemente, die Dateien sind
  • Machen Sie xargs, um jedes Element als Zeile in einen Liner bash Befehl/Skript einzugeben
  • file überprüft den Dateityp anhand des magischen Bytes, grep prüft, ob ASCII vorhanden ist. Wenn dies der Fall ist, wird nach && der nächste Befehl ausgeführt.
  • find gibt die Ergebnisse null getrennt aus. Dies ist gut, um Dateinamen mit Leerzeichen und Metazeichen zu umgehen.
  • xargs liest mit der -0-Option null getrennt, -I @@ nimmt jeden Datensatz und verwendet als Positionsparameter/args das bash -Skript.
  • -- für bash sorgt dafür, dass alles, was danach kommt, auch ein Argument ist Wenn es mit - wie -c beginnt, das sonst interpretiert werden könnteas bash-Option

Wenn Sie andere Typen als ASCII suchen müssen, ersetzen Sie einfach grep ASCII durch einen anderen Typ wie grep "PDF document, version 1.4".

0
sdkks

Ich bevorzuge Xargs

find . -type f | xargs grep -I "needle text"

wenn Ihre Dateinamen seltsam sind, suchen Sie mit den Optionen -0 nach:

find . -type f -print0 | xargs -0 grep -I "needle text"
0
dalore
  • grep eth0 $ (find/etc/-type f -exec-Datei {} \; | egrep -i "text | ascii" | cut -d ':' -f1)

grep eth0 $(find /etc/ -type f -exec file {} \; | egrep -i "text|ascii" | cut -d ':' -f1)

0
Gabriel G