ubuntuusers.de

Cat fügt falsch zusammmen

Status: Gelöst | Ubuntu-Version: Ubuntu MATE 20.04 (Focal Fossa)
Antworten |

Berlin_1946 Team-Icon

Supporter, Wikiteam

Anmeldungsdatum:
18. September 2009

Beiträge: 10841

Hallo in die Runde,

Vorgeschichte:
leider muss ich die hier beschrieben Ochsen-Tour Wiederherstellung-mittels-GPG-Tar-und-Cat fahren.

Der hier beschriebene Weg ergibt diesen nachfolgenden Inhalt.

Mit diesem Befehl:

mate-hp@matehp-HP-ProDesk:/media/mate-hp/TOSHIBA/sich-2022-07-18$ for t in duplicity-inc.20220811T071353Z.to.20220814T161732Z.*.difftar.gz; do tar xf $t; done

Damit ist u.a. dieses nachfolgende Bild bereitgestellt worden.

mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$ ls -la
insgesamt 3524
drwxrwxr-x 2 mate-hp mate-hp    4096 Aug 20 16:51 .
drwxr-xr-x 6 mate-hp mate-hp    4096 Aug 21 12:15 ..
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 1
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 10
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 11
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 12
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 13
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 14
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 15
-rwxrwxrwx 1 mate-hp mate-hp   17622 Okt 19  2004 16
-rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 2
-rwxrwxrwx 1 mate-hp mate-hp   65536>  Okt 19  2004 3
> -rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 4
> -rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 5
> -rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 6
> -rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 7
> -rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 8
> -rwxrwxrwx 1 mate-hp mate-hp   65536 Okt 19  2004 9
> mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$
> 

Jetzt zum eigentlichen Problem:

Für einzelne Dateien geht das mit dem Kommando cat. Dazu wechselt man in das Unterverzeichnis von multivolume_snapshot, das den Namen der gewünschten Datei trägt und führt den Befehl cat * > <Dateiname> aus. Die übrigen Dateien liegen im Dateibaum in multivolume_snapshot in einem Ordner pro Datei und müssen noch zusammengesetzt werden.

der Befehl ergibt Bild Dom

mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$ cat *  > Dom

Leider völliger Mist. Daher etwas gespielt und dann über diese Schritte

  • cat 1 2 3 4 5 6 7 8 9 > dom1-9

  • cat dom1-9 10 11 12 13 14 15 16 > dom1-16

das ist sehr umständlich und für eine Rettung eine sehr großen Datei wie eine *.vdi mit 1GB nicht machbar. Die Einzeldateien sind mehrere hundert a 65KB.

Wir geht das besser?

Bilder

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13365

Nicht cat ist hier der Schuldige. Du musst Dich damit beschäftigen, wie Deine Shell Glob-Muster expandiert bzw. in welcher Reihenfolge die Dateinamen aufgelistet werden. Oder Du generierst die Liste der Dateinamen selber. Zum Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
names=()

for ((i=0; 1; ++i)); do
  f="prefix-$i"

  if [ -f "$f" ]; then
    names+=("$f")
  else
    break # assume no holes
  fi
done

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7825

statt * könntest du hier {1..16} schreiben oder $(seq 1 16) falls die Shell die erste Syntax nicht kennt

wenn die Argumentliste zu lang wird, auch mit xargs kombinierbar

printf "%s\0" datei-{1..999999} | xargs -0 cat | ...

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11309

Wohnort: München

Ich würde Python nehmen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env python3
import sys
from pathlib import Path

for directory in sys.arg[1:]:
    d = Path(directory)
    if not d.is_dir():
        print(f"Warnung, {d} ist kein Verzeichnis und wird übersprungen", file=sys.stderr)
        continue
    with open(f"{d.name}_restored", 'wb') as f:
        for part in sorted((e for e in d.iterdir() if e.is_file() and e.name.isdigit()), key=lambda x: int(x)):
            f.write(part.read_bytes())

Dem ausführbar gemachten Skript kann man eines oder mehrere Verzeichnisse als Argument mitgeben. Die zusammengesetzte Datei wird im aktuellen Arbeitsverzeichnis mit dem Postfix _restored erstellt.

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1466

Man kann auch über "ls -v" zum Ziel kommen.

for t in $(ls -v duplicity-inc.20220811T071353Z.to.20220814T161732Z.*.difftar.gz); do echo $t; done

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13365

shiro schrieb:

Man kann auch über "ls -v" zum Ziel kommen.

Die Ausgabe von ls zu parsen ist immer eine schlechte Idee (siehe die zwei Links auf meiner Benutzerseite).

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7825

Variante mit Version Sort:

printf "%s\0" * | sort -z -V | xargs -0 cat

allerdings sollte man da eben auch prüfen, ob die Sortierung wirklich stimmt.

Wenn die Nummerierung keine Lücken aufweist, finde ich die Aufzählung per {1..999} intuitiver (bzw. mit seq, falls die Shell das mit {} nicht macht - Bash-spezifisch).

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1466

rklm schrieb:

Die Ausgabe von ls zu parsen ist immer eine schlechte Idee (siehe die zwei Links auf meiner Benutzerseite).

deinen Einwand bezüglich "ls" sehe ich für einen allgemeinen Anwendungsfall genauso.

Im vorliegenden Fall der Dateinamengenerierung durch "deja-dup" oder "duplicity" kann an der Stelle des "*" nur "vol[0-9]+" auftauchen. Die Gefahr, die z.B. durch eingestreute Leerzeichen im Dateinamen ausgeht, würde im konkreten Anwendungsfall nicht auftreten.

Dennoch Danke für den Hinweis auf den Seiteneffekt, der sicher nicht immer berücksichtigt wird.

Berlin_1946 Team-Icon

Supporter, Wikiteam
(Themenstarter)

Anmeldungsdatum:
18. September 2009

Beiträge: 10841

Hallo in die Runde
Danke für die Tipps.

seahawk1986 schrieb:

Ich würde Python nehmen:

Leider für mich 100% Neuland. frostschutz schrieb:

Variante mit Version Sort:

printf "%s\0" * | sort -z -V | xargs -0 cat

allerdings sollte man da eben auch prüfen, ob die Sortierung wirklich stimmt.

Wenn die Nummerierung keine Lücken aufweist, finde ich die Aufzählung per {1..999} intuitiver (bzw. mit seq, falls die Shell das mit {} nicht macht - Bash-spezifisch).

seahawk1986 schrieb:

Ich würde Python nehmen:

Den von frostschutz kann ich umsetzen. Leider nur in zwei Schritten. 1.

mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$ printf "%s\0" * | sort -z -V | xargs -0 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$ 

2.

mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$ cat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > dom
mate-hp@matehp-HP-ProDesk:/media/mate-hp/Volume/Bild1$ 

geht das auch in einem Schritt?

shiro schrieb:

Man kann auch über "ls -v" zum Ziel kommen.

for t in $(ls -v duplicity-inc.20220811T071353Z.to.20220814T161732Z.*.difftar.gz); do echo $t; done

wie baue ich den tar ein?

for t in duplicity-full.<SicherungsID>.*.difftar.gz; do tar xf $t; done 

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7825

Berlin_1946 schrieb:

geht das auch in einem Schritt?

Mir unklar, warum du zwei Schritte daraus gemacht hast.

printf "%s\0" * | sort -z -V | xargs -0 cat > dom

,


Problem bei dem Befehl ist allerdings, daß * auch die Ausgabedatei (dom) mit einschließt. Dann ist das Ergebnis wieder falsch.

Daher besser die Umleitung in ein übergeordnetes Verzeichnis machen oder eben datei* statt * Kriterium so einschränken daß * nicht den Ausgabedateinamen enthalten kann.

Also > ../datei statt > datei am Ende oder eben ... Eingabe-* ... > Ausgabe wo die Ausgabe-Datei nicht Teil der Eingabe-* Dateien sein kann

Denn da können lustige Dinge passieren, wenn cat die Datei wieder einliest, die die Shell/Pipe/Umleitung gerade rausschreibt... das hört dann ggf. nicht auf, bis die Platte voll ist.


cat versucht diesen Fall auch zu erkennen und quittiert dann mit dem Fehler "input file is output file" aber das klappt je nach Pipe-Konstellation eben auch nicht immer.

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1466

Berlin_1946 schrieb:

wie baue ich den tar ein?

Na ja, um die Bedenken von rklm zu berücksichtigen, würde ich den "ls" Befehl mit einer regex formulieren, dass nach dem "vol" nur Zahlen (mindestens eine wegen "+") vorkommen dürfen also keine Blanks, z.B. so:

SicherungsID="20220811T071353Z"
for t in $(ls -v duplicity-full.$SicherungsID.vol+([0-9]).difftar.gz); do tar xf $t; done 

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4784

Wohnort: Berlin

seahawk1986 schrieb:

Ich würde Python nehmen: […]

Da sind mir ja ein paar zu viele einbuchstabige Namen drin. Bei sys.argv fehlt das v.

continue macht Programme unübersichtlicher weil man diesen Sprung nicht an der Einrückung erkennen kann. Man kann dann auch keinen Code mehr hinzufügen der am Ende jedes Schleifendurchlaufs ausgeführt wird, und Code aus dem Schleifenkörper in eine Funktion heraus ziehen wird auch komplizierter wenn da ein continue drin ist.

Das key-Argument braucht keinen lambda-Ausdruck, da kann man einfach direkt int übergeben.

Ungetestet:

 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
#!/usr/bin/env python3
import sys
from pathlib import Path


def main():
    for source_directory_path in map(Path, sys.argv[1:]):
        if source_directory_path.is_dir():
            target_file_path = Path(f"{source_directory_path.name}_restored")
            with target_file_path.open("wb") as restored_file:
                for part_path in sorted(
                    (
                        path
                        for path in source_directory_path.iterdir()
                        if path.name.isdigit() and path.is_file()
                    ),
                    key=int,
                ):
                    restored_file.write(part_path.read_bytes())
        else:
            print(
                f"Warnung, {source_directory_path!r} ist kein Verzeichnis und"
                f" wird übersprungen",
                file=sys.stderr,
            )


if __name__ == "__main__":
    main()

Mögliches Problem: Die nummerierten Einzeldateien werden (einzeln) komplett in den Arbeitsspeicher geladen. Falls eine Einzeldatei zu gross ist, gäbe es da Werkzeuge im shutil-Modul in der Standardbibliothek.

Berlin_1946 Team-Icon

Supporter, Wikiteam
(Themenstarter)

Anmeldungsdatum:
18. September 2009

Beiträge: 10841

shiro schrieb:

SicherungsID="20220811T071353Z"
for t in $(ls -v duplicity-full.$SicherungsID.vol+([0-9]).difftar.gz); do tar xf $t; done 

frostschutz schrieb:

printf "%s\0" * | sort -z -V | xargs -0 cat > dom

Problem bei dem Befehl ist allerdings, daß * auch die Ausgabedatei (dom) mit einschließt. Dann ist das Ergebnis wieder falsch. Daher besser die Umleitung in ein übergeordnetes Verzeichnis machen

So habe ich aus der Kombination der beiden Antworten bzw Befehlen viele Dateien retten können. Der vorgenannte Hinweis - den * betreffend - ist im folgenden Befehl berücksichtigt.

printf "%s\0" * | sort -z -V | xargs -0 cat > /home/mate-hp/Schreibtisch/dom

Danke allen für die Unterstützung. Ich stelle auf gelöst.

Antworten |