2017-08-19 3 views
0

Ich versuche Whitespace in Dateinamen zu entfernen und sie zu ersetzen.sed/awk - Leerzeichen im Dateinamen entfernen

Eingang:

echo "File Name1.xml File Name3 report.xml" | sed 's/[[:space:]]/__/g' 

jedoch der Ausgang

File__Name1.xml__File__Name3__report.xml 

Wunsch Ausgang

File__Name1.xml File__Name3__report.xml 
+2

Wo sind die Dateinamen kommen? Awk kann angewiesen werden, auf Zeilenumbrüche zu begrenzen, die dann leichter Übereinstimmungen in einem Muster sein können. – linden2015

+0

Haben die Dateinamen die gleiche '.xml' Erweiterung? –

+0

Ja, sie sind alle '.xml' Dateien – Deano

Antwort

1

Sie benannt awk im Titel der Frage, nicht wahr?

$ echo "File Name1.xml File Name3 report.xml" | \ 
> awk -F'.xml *' '{for(i=1;i<=NF;i++){gsub(" ","_",$i); printf i<NF?$i ".xml ":"\n" }}' 
File_Name1.xml File_Name3_report.xml 
$ 
  • -F'.xml *'awk anweist, auf einem regulären Ausdruck aufzuspalten, der gewünschten Verlängerung plus 0 oder mehr Räume
  • die Schleife {for(i=1;i<=NF;i++) für alle Felder in der ausgeführt wird, die Eingangsleitung (en) ist (sind) gespaltet - beachten sie, dass das letzte Feld leer ist (es ist das, was die letzte Erweiterung folgt), aber wir werden das berücksichtigen ...
    der Körper der Schleife
    • gsub(" ","_", $i) Ersatz alle Vorkommen von Raum im aktuellen Feld unterstreicht, durch die Schleifenvariable indiziert als i
    • printf i<NF?$i ".xml ":"\n" Ausgabe verschiedene Dinge, wenn i<NF es ein reguläres Feld ist, so dass wir die Erweiterung und einen Raum anzuhängen, NFi gleich andernfalls wir Ich möchte nur die Ausgabezeile mit einem Zeilenumbruch beenden.

Es ist nicht perfekt, fügt es einen Raum nach dem letzten Dateinamen. Ich hoffe, das ist gut genug ...


▶ A D D E N D U M ◀

Ich mag würde adressieren:

  • das kleine buglet des letzten Raum ...
  • einige the issues reported von Ed Morton
  • verallgemeinern die Erweiterung zur Verfügung gestellt awk

Um diese Ziele zu erreichen, habe ich beschlossen, die scriptlet in einer Shell-Funktion, dass das Ändern Räume in Unterstrichen wickeln s2u

$ s2u() { awk -F'\.'$1' *' -v ext=".$1" '{ 
> NF--;for(i=1;i<=NF;i++){gsub(" ","_",$i);printf "%s",$i ext (i<NF?" ":"\n")}}' 
> } 
$ echo "File Name1.xml File Name3 report.xml" | s2u xml 
File_Name1.xml File_Name3_report.xml 
$ 

Es ist ein bisschen anders genannt wird (besser?) ‚Cs es tut nicht Sonderdruck das letzte Feld, sondern Sonderfälle das Begrenzungszeichen an jedes Feld angehängt, aber die Idee der Teilung auf der Erweiterung bleibt.

+0

Danke für Ihre detaillierte Antwort, ich habe viel gelernt :) – Deano

+1

Das wird einen Syntaxfehler in einigen Awks aufgrund der ungeparenthesized ternären Ausdruck verursachen und es wird cryptisch fehlschlagen, wenn ein Dateiname printf Formatierungszeichen enthält, z. 'big% slip.xml' - verwende immer 'printf'% s ', $ i' anstelle von' printf $ i'. Anstatt den Wert hart zu codieren, von dem Sie hoffen, dass der ORS verwendet wird, verwenden Sie einfach am Ende des Ausdrucks "ORS" statt "". Sie könnten '[[:: space:]] verwenden. + 'statt' '' 'auch in den Registern -F und gsub. –

+0

Einige 'awk's haben keine regexp Zeichenklassen ... und ich möchte nicht den Standard' ORS' verwenden, ich möchte einen Zeilenumbruch! Nichtsdestoweniger habe ich Ihren Vorschlag über Klammern in ternären Ausdrücken und die korrekte Verwendung von 'printf' implementiert, auch das letzte leere Buglet währenddessen korrigiert. TX – gboffi

0

Dies scheint einen guten Start, wenn die Dateinamen nicht abgegrenzt werden:

((?:\S.*?)?\.\w{1,})\b 

(  // start of captured group 
(?:  // non-captured group 
\S.*? // a non-white-space character, then 0 or more any character 
)?  // 0 or 1 times 
\.  // a dot 
\w{1,} // 1 or more word characters 
)  // end of captured group 
\b  // a word boundary 

Sie müssen nachsehen, wie ein PCRE-Muster in ein Shell-Muster konvertiert wird. Alternativ kann es von einem Python/Perl/PHP-Skript ausgeführt werden. alle Räume der XML-Dateien ersetzt Diese

rename --nows *.xml 

mit _ im aktuellen Ordner:

Demo

-1

Sie rename nutzen könnten.

Manchmal kommt es ohne die --nows Option, so dass Sie dann eine Suche verwenden können und ersetzen:

rename 's/[[:space:]]/__/g' *.xml 

Schließlich können Sie --dry-run verwenden, wenn Sie nur Dateinamen drucken möchten, ohne die Namen zu bearbeiten.

+0

Bitte lesen Sie die Frage. Das OP hat nicht gebeten, die Dateien umzubenennen. Vielleicht werden sie die Frage ändern, aber im Moment haben Sie eine andere Frage beantwortet. – gboffi

+1

Ich weiß nicht, was op am Ende machen will (und ich habe '--dry-run' zu diesem Zweck gegeben). Aber von 'Leerzeichen im Dateinamen entfernen 'nehme ich klar an, dass meine Antwort auch wenn nicht die akzeptierte, immer noch am Thema ist ... –

+0

Die OP Frage betrifft eine Zeichenkette mit Dateinamen, wie die' --dry-run' Option helfen könnte Sie? Meiner Meinung nach sollte Ihre Antwort als Kommentar neu formuliert werden. "" Werden Sie nicht zufällig nach dem Umbenennen dieser Dateien sein? "_ – gboffi

0

Angenommen, Sie fragen, wie Dateinamen umbenannt werden und Leerzeichen in einer Liste von Dateinamen, die aus einem anderen Grund verwendet werden, nicht entfernt werden, ist dies der lange und kurze Weg. Der lange Weg benutzt sed. Der kurze Weg verwendet Umbenennen. Wenn Sie nicht versuchen, Dateien umzubenennen, ist Ihre Frage ziemlich unklar und sollte überarbeitet werden.

Wenn das Ziel ist, einfach eine Liste von XML-Dateinamen zu bekommen und sie mit sed zu ändern, ist das untere Beispiel, wie man das macht.

Verzeichnisinhalt:

ls -w 2 
bob is over there.xml 
fred is here.xml 
greg is there.xml 

cd [directory with files] 
shopt -s nullglob 
a_glob=(*.xml); 
for ((i=0;i< ${#a_glob[@]}; i++));do 
    echo "${a_glob[i]}"; 
done 
shopt -u nullglob 
# output 
bob is over there.xml 
fred is here.xml 
greg is there.xml 

# then rename them 
cd [directory with files] 
shopt -s nullglob 
a_glob=(*.xml); 
for ((i=0;i< ${#a_glob[@]}; i++));do 
    # I prefer 'rename' for such things 
    # rename 's/[[:space:]]/_/g' "${a_glob[i]}"; 
    # but sed works, can't see any reason to use it for this purpose though 
    mv "${a_glob[i]}" $(sed 's/[[:space:]]/_/g' <<< "${a_glob[i]}"); 
done 
shopt -u nullglob 

Ergebnis:

ls -w 2 
bob_is_over_there.xml 
fred_is_here.xml 
greg_is_there.xml 

Globbing ist, was Sie wegen der Räume in den Namen hier möchten.

Dies ist jedoch wirklich eine komplizierte Lösung, wenn eigentlich alles, was Sie tun müssen, ist:

cd [your space containing directory] 
rename 's/[[:space:]]/_/g' *.xml 

und das ist es, sind Sie fertig.

Wenn Sie auf der anderen Seite versuchen, eine Liste von Dateinamen zu erstellen, möchten Sie sicherlich die Globbing-Methode, die, wenn Sie nur die Anweisung ändern, tun, was Sie auch dort wollen, das heißt, nur verwenden sed, um den Namen der Ausgabedatei zu ändern.

Wenn Ihr Ziel ist es, die Dateinamen zu Ausgabezwecken zu ändern, und nicht die eigentlichen Dateien umbenennen:

cd [directory with files] 
shopt -s nullglob 
a_glob=(*.xml); 
for ((i=0;i< ${#a_glob[@]}; i++));do 
    echo "${a_glob[i]}" | sed 's/[[:space:]]/_/g'; 
done 
shopt -u nullglob 
# output: 
bob_is_over_there.xml 
fred_is_here.xml 
greg_is_there.xml 
Verwandte Themen