Konvertieren Sie nur Teile eines Dateinamens in Großbuchstaben

Konvertieren Sie nur Teile eines Dateinamens in Großbuchstaben

In einem Shell-Skriptprogramm muss ich die Dateinamen in Großbuchstaben umwandeln, wenn der umgewandelte Dateiname noch nicht existiert. In diesem speziellen Fall muss ich nur den Basisnamen in Großbuchstaben ändern und die Erweiterung (falls vorhanden) unverändert lassen.

Meine Idee zur Lösung des Problems besteht darin, zuerst den Basisnamen und die Erweiterung separat zu extrahieren, den Basisnamen mithilfe treines Befehls in Großbuchstaben umzuwandeln und dann zu prüfen, ob der geänderte Basisname zusammen mit der Erweiterung im Verzeichnis vorhanden ist oder nicht.

Wenn es nicht existiert, ersetze ich den ursprünglichen Dateinamen mit mv durch den Basisnamen in Großbuchstaben. Ich denke, das kann auf zwei Arten geschehen: erstens durch Verwendung exprund zweitens durch Verwendung cutvon .(Leerzeichen-Punkt-Leerzeichen) als Trennzeichen.

exprWenn ich zum Extrahieren des Basisnamens (also zB aus dem Dateinamen - python1.pyoder ) verwenden möchte, phonelistdann habe ich folgendes geschrieben:

basefile=`expr "$filename" : '\(.*\)\.*.*' ` 

Ich habe es \.*auch für Dateinamen verwendet, die keine Erweiterung haben, da \.* null oder mehr Vorkommen von ignoriert würden ., aber dieser Ausdruck exprfunktioniert nicht richtig. Für jeden Dateinamen wird der gesamte Dateiname so zurückgegeben, wie er ist.

Kann mir bitte jemand erklären, wo ich falsch liege? Bitte geben Sie mir auch einen Tipp, wie ich exprnur die Erweiterung aus dem Dateinamen extrahieren kann.

Antwort1

Wenn die Shell ist bash, verwenden Sie einfach die Bash-Parametererweiterung:

file="aaa.bbb.dat"

name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything

echo "$upcase"
AAA.BBB.dat

Versuchen wir es mit einem schwierigeren Fall:

file="déjà vu . dat "
name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything
echo ":$upcase:"

Gibt:

:DÉJÀ VU . dat :

Also:

  • Anführungszeichen sind nicht erforderlich, bis das Ergebnis verwendet wird
  • Großbuchstaben scheinen auch bei Nicht-ASCII-Zeichen in Ordnung zu sein

Antwort2

Wenn es Unklarheiten darüber gibt, wie weit sich eine Gruppe erstreckt, bevorzugen Regex-Engines zuerst die längste Übereinstimmung. Für jeden Dateinamen \(.*\)wird der gesamte Name und \.*.*die leere Zeichenfolge abgeglichen.

Sie benötigen zwei Fälle: mit oder ohne Erweiterung. Beachten Sie auch, dass ein Dateiname, der mit einem beginnt ., nicht der Anfang einer Erweiterung ist.

Ich verstehe nicht, warum Sie verwenden möchten expr. Die Manipulation von Shell-Parametern ist einfacher.

Beachten Sie beim Konvertieren in Großbuchstaben, dass die trImplementierung unter Linux keine Nicht-ASCII-Gebietsschemas unterstützt. Es werden nur Bytemanipulationen durchgeführt. Beispielsweise echo accentué | tr a-z A-Zergibt dies ACCENTUé, nicht ACCENTUÉ. Verwenden Sie stattdessen ein lokalfähiges Tool wie awk. In Bash können Sie verwenden ${filename^^?}, aber das ist in SH nicht verfügbar. Stellen Sie sicher, dass Ihr Skript im richtigen Gebietsschema für die Kodierung der Dateinamen ausgeführt wird.

Ich gehe davon aus, dass der Dateiname keinen Verzeichnisteil enthält. Wenn doch, trennen Sie ihn zuerst.

case $filename in
  ?*.*) # There is an extension
    base="${filename%.*}"; ext=".${filename##*.}";;
  *) # No extension
    base="$filename"; ext="";;
esac
upcased_base="$(printf %s. %base | awk '$0 = toupper($0)')"
upcased="${upcased_base%.}$ext"

Das anschließende Entfernen des Endzeichens .stellt sicher, dass das Skript Dateinamen mit einem Zeilenumbruch unmittelbar vor der Erweiterung korrekt verarbeitet. Ohne dieses würde die Befehlsersetzung nachfolgende Zeilenumbrüche entfernen. Sie benötigen dies nicht, wenn Sie bereits sichergestellt haben, dass Ihre Dateinamen keine Zeilenumbruchzeichen enthalten.%s.$upcased_base

Antwort3

Hier ist eine vollständig awkauf -basierte Lösung, bei der Sie die folgende Zeile in Ihr Shell-Skript einfügen würden:

uppercasename="$(echo "$filename" | awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1')"

.Dabei wird der Feldtrenner „as“ verwendet.für Ein- und Ausgabeund wenn nur ein Feld gefunden wird, wird dieses in Großbuchstaben umgewandelt. In allen anderen Fällen werden alle Felder außer dem letzten in Großbuchstaben umgewandelt. Anschließend wird das Ergebnis gedruckt (das ist die Bedeutung von 1, einer Kurzschreibweise für {print}).

Wenn Sie verwenden bash, können Sie das Pipe-Zeichen entfernen und es als

uppercasename="$(awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1' <<< "$filename")"

mithilfe eines Here-Strings.

Beachten Sie, dass dies so konzipiert ist, dass im Grenzfall eines Dateinamens, der mit einem endet ., wie in myfile.this.txt., dies wie ein „leeres, aber vorhandenes Suffix“ behandelt und in konvertiert wird MYFILE.THIS.TXT.. Auch wenn der Dateinamebeginntmit einem .und hat keine andere Erweiterung (wie in .myfile), wird es in Kleinbuchstaben belassen.

verwandte Informationen