Tids
Anmeldungsdatum: 29. Oktober 2008
Beiträge: 3065
Wohnort: Naumburg (Saale)
|
Das beschäftigt mich schon ein Weilchen. Ich suche nach einer Möglichkeit bestimmte Dateiengruppen zu suchen. Dabei darf der Dateiname keine Rolle spielen, was die Endung einbezieht. file TAKEASMILE.jpg
TAKEASMILE.jpg: PDF document, version 1.4 Hintergrund ist der, dass ich viele viel viele Bilder habe die entweder komplett ohne Endung sind oder aber die falsche haben. Es sollte sich aber nicht auf Bilder beziehen, sondern einen von mir vorgegeben Dateityp finden. dazu wäre es hilfreich wenn ich einen bestimmten Wert aus 'file' angeben kann und er mein $HOME durchsucht und eine Liste der gefundenen Dateien ausgibt. ich bin mir sicher das sich das irgendwie mittels file und find lösen lässt, ich komme nur leider nicht drauf wie. Hoffentlich kann mir da jemand helfen oder mich zumindest in die richtige Richtung stoßen.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11273
Wohnort: München
|
Wie wäre mit so einem Ansatz? Man lässt den Dateityp von file bestimmen und filtert mit grep nach dem gewünschten String:
find verzeichnis/ -type f -exec file {} \; | grep "PDF document"
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Vielleicht würde man den Ansatz noch um eine Untershell erweitern. In der kann man bequem den Zauber einbauen, den man braucht: | find verzeichnis -type f -exec bash -c 'file {} | grep -q "PDF document" && echo "zauber-zauber"' \;
|
LG, track
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11273
Wohnort: München
|
Wäre es es nicht effizienter das nachträglich zu filtern als da jedes Mal eine neue Subshell aufzumachen?
| find "$HOME" -type f -exec file {} \; | sed -nE 's/^(.*):.*PDF\ document.*/\1/p'
|
Vor allem wenn man da mehrere Aufrufe hintereinander für verschiedene Dateitypen macht, kann man sich die Liste so auch vorab erstellen lassen, in eine Datei schreiben und braucht die dann nur noch filtern.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Es kommt eben drauf an, was Tids am Ende vorhat ... Man muss sich halt nur dessen bewusst sein, dass Zeilenumbrüche und ähnliche Gemeinheiten evt. dann die ganze Geschichte sprengen können: track@track:~$ file ./-test/*
./-test/8158133-Anhang.csv: UTF-8 Unicode text
./-test/8158133-Anhang.csv.neu: UTF-8 Unicode text, with CRLF line terminators
./-test/achdu�schreck!: ASCII text
./-test/AVSEQ01.DAT: ASCII text
./-test/AVSEQ01.DAT.BAK: ASCII text
./-test/AVSEQ01.DAT.son: Little-endian UTF-16 Unicode text
./-test/das hier ist gemein: \n ... kein echtes newline: ASCII text
./-test/Ers�tzz�ich�n: empty
./-test/gnu > *: ASCII text
./-test/ich bin
böse: ASCII text
./-test/-n: UTF-8 Unicode text
./-test/test datei
mit Gift ('Kopie").txt: ASCII text
./-test/ vorn 2 leer: empty
./-test/wort_mit_�h=öh.: empty und das kriegt man halt nur mit peinlich sauberem Arbeiten in den Griff. LG, track
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11273
Wohnort: München
|
Oder man wechselt von der Shell in eine Skriptsprache, die mit problematischen Zeichen in Pfaden leichter umgehen kann - mit ein bisschen Magie (Paket python3-magic unter Ubuntu) z.B. so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | #!/usr/bin/env python3
import argparse
import magic
import os
m=magic.open(magic.MAGIC_NONE)
m.load()
parser = argparse.ArgumentParser(description='filter files in a directory by file type')
parser.add_argument('directories', metavar='directory', nargs='+',
help='directory to search')
parser.add_argument('--search', '-s', default=None,
help='string to search in file type description')
args = parser.parse_args()
for dir in args.directories:
for root, dirnames, filenames in os.walk(dir):
for filename in filenames:
path = os.path.join(root, filename)
filetype = m.file(path)
if args.search and args.search in filetype:
print(path)
elif not args.search:
print(path + ":", filetype)
|
Das nimmt dann einen (optionalen) Suchbegriff und einen oder mehrere Ordner, die durchsucht werden sollen:
$ python3 search_by_filedesc.py -h
usage: search_by_filedesc.py [-h] [--search SEARCH] directory [directory ...]
filter files in a directory by file type
positional arguments:
directory directory to search
optional arguments:
-h, --help show this help message and exit
--search SEARCH, -s SEARCH
string to search in file type description Ohne Suchbegriff listet es den Pfad und die Dateibeschreibung, mit Suchbegriff nur den Pfad für Treffer auf:
$ python3 search_by_filedesc.py test/
test/search_by_filedesc.py: Python script, ASCII text executable
test/original_mac.txt: ASCII text
test/lircd.org: UTF-8 Unicode text
$ python3 search_by_filedesc.py -s "UTF-8" test/
test/lircd.org
|
Tids
(Themenstarter)
Anmeldungsdatum: 29. Oktober 2008
Beiträge: 3065
Wohnort: Naumburg (Saale)
|
Danke so weit erst einmal. Was ich am Ende vor habe ich "ganz einfach". Je nachdem was für ein Dateityp will ich unterschiedliche Befehle mit dieser Datei ausführen. z.B. die einen Umbenennen, andere umwandeln.
Gibts da irgendwas um für jede gefundene Datei eine Reihe von anderen Befehlen mit rein zu bauen? nehmen wir mal einen ganz utopischen Fall, bei gefundene jpeg Dateien die ich nach *.webp umwandeln will. das wären dann
du -h <datei>
cwebp -q80 <datei> -o <datei>.webp
rm <datei>
du -h <datei>.webp wie gesagt, ist frei erfunden. Nur möchte ich eben auch mit den Dateien "arbeiten".
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11273
Wohnort: München
|
Da könnte man bei der Python-Lösung noch eine Option für die Ausführung von Befehlen einbauen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | #!/usr/bin/env python3
import argparse
import magic
import os
import subprocess
my_env = os.environ
m=magic.open(magic.MAGIC_NONE)
m.load()
parser = argparse.ArgumentParser(description='filter files in a directory by file type')
parser.add_argument('directories', metavar='directory', nargs='+',
help='directory to search')
parser.add_argument('--search', '-s', default=None,
help='string to search in file type description')
parser.add_argument('--command', '-c', default=None,
help=('execute command on each filtered file - '
'this is only executed if a search argument is given - '
'the path is exported as environment variable "$match"'))
args = parser.parse_args()
for dir in args.directories:
for root, dirnames, filenames in os.walk(dir):
for filename in filenames:
path = os.path.join(root, filename)
filetype = m.file(path)
if args.search and args.search in filetype:
if not args.command:
print(path)
else:
my_env['match'] = path
subprocess.call(args.command, shell=True, env=my_env)
elif not args.search:
print(path + ":", filetype)
|
Dann kannst du einen Befehl oder ein Skript ausführen lassen, das den Pfad zur jeweiligen Datei als Umgebungsvariable "${match}" nutzen kann:
$ python3 search_by_filedesc.py -s JPEG -c 'du -h "$match"; cwebp -q 80 "$match" -o "${match}.webp"; du -h "${match}.webp"' test
4,0K test/background.jpg
Saving file 'test/background.jpg.webp'
File: test/background.jpg
Dimension: 9 x 9
Output: 56 bytes Y-U-V-All-PSNR 44.39 99.00 99.00 46.15 dB
block count: intra4: 0
intra16: 1 (-> 100.00%)
skipped block: 0 (0.00%)
bytes used: header: 6 (10.7%)
mode-partition: 3 (5.4%)
Residuals bytes |segment 1|segment 2|segment 3|segment 4| total
macroblocks: | 100%| 0%| 0%| 0%| 1
quantizer: | 19 | 19 | 19 | 19 |
filter level: | 5 | 5 | 5 | 5 |
4,0K test/background.jpg.webp Statt einer Befehlsabfolge kannst du natürlich auch ein ausführbares Skript übergeben, dass die gefundenen Dateien manipuliert:
| #!/bin/bash
if [[ -z "$match" ]]; then
match="$1"
fi
du -h "$match"
cwebp -q 80 "$match" -o "${match}.webp"
du -h "${match}.webp"
|
$ python3 search_by_filedesc.py -s 'JPEG image data' -c './convert_to_webp.sh' test
4,0K test/background.jpg
Saving file 'test/background.jpg.webp'
File: test/background.jpg
Dimension: 9 x 9
Output: 56 bytes Y-U-V-All-PSNR 44.39 99.00 99.00 46.15 dB
block count: intra4: 0
intra16: 1 (-> 100.00%)
skipped block: 0 (0.00%)
bytes used: header: 6 (10.7%)
mode-partition: 3 (5.4%)
Residuals bytes |segment 1|segment 2|segment 3|segment 4| total
macroblocks: | 100%| 0%| 0%| 0%| 1
quantizer: | 19 | 19 | 19 | 19 |
filter level: | 5 | 5 | 5 | 5 |
4,0K test/background.jpg.webp Bei der Shell-Lösung von track mit find würde das z.B. so gehen:
| $ find test -type f -exec bash -c 'file "$0" | grep -q "JPEG image data" && "./convert_to_webp.sh" "$0"' {} \;
|
Was für dich nützlicher ist, dürfte davon abhängen, womit du mehr Skripting-Erfahrung hast und ob es lustige Sonderzeichen in deinen Pfaden gibt, die das Shell-Skripting weniger praktikabel machen.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13227
|
seahawk1986 schrieb: Wäre es es nicht effizienter das nachträglich zu filtern als da jedes Mal eine neue Subshell aufzumachen?
| find "$HOME" -type f -exec file {} \; | sed -nE 's/^(.*):.*PDF\ document.*/\1/p'
|
Was ist sed -Option "-E"? Ich kann die in keiner Manpage finden. Außerdem brauchst Du für den Ausdruck oben "-r", sonst musst Du die Klammern mit Backslash zu Meta-Zeichen machen. Wenn Du schon am optimieren bist, dann solltest Du auch die Form nehmen, die file nicht extra für jede einzelne Datei aufruft: | find "$HOME" -type f -exec file {} + | sed -nre 's/^(.*): +PDF document.*$/\1/p'
|
Ich habe auch noch den Ausdruck etwas verändert.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11273
Wohnort: München
|
rklm schrieb: Was ist sed -Option "-E"? Ich kann die in keiner Manpage finden. Außerdem brauchst Du für den Ausdruck oben "-r", sonst musst Du die Klammern mit Backslash zu Meta-Zeichen machen.
Das stammt ursprünglich von BSD (https://www.freebsd.org/cgi/man.cgi?query=sed&sektion=&n=1), funktioniert aber auch schon länger mit GNU sed und macht laut Quellcode das selbe wie "-r".
Im Quellcode war das schon bei der Version 4.1a (die müsste in etwa von 2008 gewesen sein): http://git.savannah.gnu.org/cgit/sed.git/tree/sed/sed.c?id=v4.1a#n259 Aber der Commit, der die Dokumentation dafür nachrüstet, hat es wohl noch nicht in ein offizielles Release geschafft: http://git.savannah.gnu.org/cgit/sed.git/commit/?id=8b65e07904384b529a464c89f3739d2e7e4d5135
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13227
|
seahawk1986 schrieb: rklm schrieb: Was ist sed -Option "-E"? Ich kann die in keiner Manpage finden. Außerdem brauchst Du für den Ausdruck oben "-r", sonst musst Du die Klammern mit Backslash zu Meta-Zeichen machen.
Das stammt ursprünglich von BSD (https://www.freebsd.org/cgi/man.cgi?query=sed&sektion=&n=1), funktioniert aber auch schon länger mit GNU sed und macht laut Quellcode das selbe wie "-r".
Im Quellcode war das schon bei der Version 4.1a (die müsste in etwa von 2008 gewesen sein): http://git.savannah.gnu.org/cgit/sed.git/tree/sed/sed.c?id=v4.1a#n259 Aber der Commit, der die Dokumentation dafür nachrüstet, hat es wohl noch nicht in ein offizielles Release geschafft: http://git.savannah.gnu.org/cgit/sed.git/commit/?id=8b65e07904384b529a464c89f3739d2e7e4d5135
Erschreckend.
|
Tids
(Themenstarter)
Anmeldungsdatum: 29. Oktober 2008
Beiträge: 3065
Wohnort: Naumburg (Saale)
|
seahawk1986 schrieb:
Bei der Shell-Lösung von track mit find würde das z.B. so gehen:
| $ find test -type f -exec bash -c 'file "$0" | grep -q "JPEG image data" && "./convert_to_webp.sh" "$0"' {} \;
|
Danke. So funktioniert es perfekt ☺ Was für dich nützlicher ist, dürfte davon abhängen, womit du mehr Skripting-Erfahrung hast und ob es lustige Sonderzeichen in deinen Pfaden gibt, die das Shell-Skripting weniger praktikabel machen.
Auf jeden Fall Shellscriptiing. Mit Python kann ich nicht wirklich was anfangen :s Vielen dank nochmal an dich und an alle anderen die geholfen haben (:
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13227
|
Tids schrieb: seahawk1986 schrieb:
Bei der Shell-Lösung von track mit find würde das z.B. so gehen:
| $ find test -type f -exec bash -c 'file "$0" | grep -q "JPEG image data" && "./convert_to_webp.sh" "$0"' {} \;
|
Danke. So funktioniert es perfekt ☺
Ehrlich gesagt, wenn man sowieso bereits convert_to_webp.sh hat, dann kann man die komplette Logik dort versenken und sich bash -c "..." beim Aufruf von find sparen. Dann macht man das gleich so: | #!/bin/sh
for f; do
if file "$f" | fgrep -q 'JPEG image data'; then
# do conversion
else
echo "Ignoring: $f" >&2
fi
end
|
Der else -Zweig kann natürlich auch weggelassen werden. Und: | find test -type f -exec ./convert_to_webp.sh {} +
|
|