2016-04-04 1 views
2

Derzeit in cron den Befehl Ich verwende Kopie *.data von Quelle zu machen Weg zum Ziel:`finden -name` mit RegexMuster und den Dateinamen Austausch mit` cp`

find /source_path -name *.data -exec cp {} /target_path \; 

Die Quelle Struktur ist:

/source_path/category1/001.data 
    /source_path/category1/002.data 
    /source_path/category2/003.data 
    /source_path/category3/004.data 
    /source_path/categorya/005.data 
    /source_path/categoryb/006.data 

Nach dem obigen cron Befehl, wird das Ziel enthalten:

/target_path/001.data 
    /target_path/002.data 
    /target_path/003.data 
    /target_path/004.data 
    /target_path/005.data 
    /target_path/006.data 

Ich brauche eine einzeilige Lösung meinen aktuellen cron Befehl zu ersetzen, so dass nach der Ausführung, enthält das Ziel:

/target_path/category1_001.data 
    /target_path/category1_002.data 
    /target_path/category2_003.data 
    /target_path/category3_004.data 
    /target_path/categorya_005.data 
    /target_path/categoryb_006.data 

Um Unterverzeichnisnamen als Präfix des Zieldateinamen anhang.

Danke.

+1

'sed -r -e 's/\/source (_pfad) \/(kategorie. +) \/([0-9] + \. data)/\/ziel \ 1 \/\ 2_ \ 3/gm' source_file> target_file' – rock321987

+0

Was macht dieser Code? Ich bin nicht vertraut mit Sed, aber es sieht aus wie Substitution zu mir.Überquert es den Quellpfad und kopieren Sie von der Quelle zum Ziel? Auch, "Kategorie" könnte alles, co sein Bindestriche, Unterstriche, etc, nicht nur mit der Wortkategorie beginnen. Danke – KDX

+0

Sie haben es richtig..Es ist Substitution.Ich gehe davon aus, dass diese Pfade in einer Datei sind und ändern Sie es und speichern Sie es in einer anderen Datei..Wollen Sie dies oder etwas anderes? – rock321987

Antwort

2

Prüfen Sie diesen Befehl, die nur Zeichenketten druckt:

$ find /source_path -name \*.data | while read -r filename; do printf "print version: cp %s %s\n" "${filename}" "$(printf "%s\n" "${filename}" | sed "s/^.*[/]\(category[^/]*\)[/]\(.*[.]data\)$/\/target_path\/\1_\2/")"; done 

finden Befehl druckt die Dateinamen gefunden, eine pro Zeile.

lesen -r Dateiname eine Zeile Text lesen und speichern sie in Dateinamen Variable.

finden ... | Beim Lesen -r Dateiname schreiben Sie eine Liste von Dateinamen, eine pro Zeile, in die Pipe. Es wird jeweils nur ein Dateiname gelesen. Für jeden gelesenen Dateinamen wird der Befehl in den Block während ausgeführt.

Der sed Befehl einen Pfadnamen /source_path/category1/001.data in ändert /target_path/category1_001.data.

versuchte ich mein Bestes, um das String-Argument von sed in den folgenden Zeilen zu erklären, aber wenn Sie in diesen Themen sind interresting sollten Sie lesen:

s/ ist der Befehl search and replace sed, gefolgt von 3 Elementen: "s/regex pattern/replacement/flag"

^ am Anfang bedeutet, Start der Linie.

. bedeutet ein beliebiges Zeichen.

* bedeutet 0 oder eine unendliche Zahl des zuvor angegebenen Zeichens.

[/] bedeutet ein Zeichen, das Zeichen /. [] Wird verwendet als Trennzeichen zwischen RegexMuster entweichen / andernfalls wird es, Ersatz interpretiert und Flag.

Alles in allem ^. * [/] bedeutet eine Linie mit beliebigen null oder mehr Zeichen beginnen. Diese Startsequenz muss mit / enden.

[^ /] bedeutet ein Zeichen, ^ bei Start bedeutet nicht Teil des Char aufgeführt. Also, es bedeutet eine beliebige Char außer der /.

[abc] zwischen [], bedeutet ein Zeichen: entweder a entweder b entweder c.

Die erste \ (. * \) im Muster regex angetroffen kann mit \ 1 in Ersatz referenziert werden. Die zweite \ (. * \) im RegexMuster angetroffen mit \ 2 in Ersatz referenziert werden. Ohne usw. \ Flucht char, ( bedeutet ein einzelnes Zeichen (, und der Inhalt nicht verwiesen werden kann

Bei Verwendung cp getan stattdessen effektiv die Dateien zu kopieren.

find /source_path -name \*.data | while read -r filename; do cp "${filename}" "$(printf "%s\n" "${filename}" | sed "s/^.*[/]\(category[^/]*\)[/]\(.*[.]data\)$/\/target_path\/\1_\2/")"; done 
+0

Diese Lösung funktioniert bei mir im Testlauf in Druckzeichenfolgen. Ich habe den eigentlichen Lauf noch nicht durchgeführt. Ich ersetzte '(Kategorie [^ /] * \)' durch '(. * [^ /] * \)', Um jedes mögliche Zeichen zu finden, da die Kategorie eigentlich unterschiedliche Namen hat. Können Sie mir eine kurze Erklärung geben? Ist das nicht lesbar für mich? Was bedeutet 'while read -r filename' und interagiert mit' find' oder 'sed'? Auch der reguläre Ausdruck von '[/]', '[^ /]', und auch warum entkommst du Klammern? Was sind die Klammern? Dank. – KDX

+1

@KDX Die Antwort wurde mit eplanations aktualisiert. –

+0

Danke für die ausführlichen Erklärungen. Alles verstanden. Wie wäre es mit '^. *' Am Anfang? Passt es zu null oder mehr Nicht-Zeichen oder null oder mehr Zeichen? Ohne \ escape char, was bedeutet das? Ich erinnere mich nicht an die Notwendigkeit, Klammern in anderen Programmiersprachen zu umgehen zB Perl/PHP – KDX