Verwendung von Dateinamen, die mit einem Punkt enden

7

Warum erlaubt Unix Dateien mit einem Punkt am Ende des Namens? Gibt es eine Verwendung dafür?

Zum Beispiel:

filename.

Ich frage, weil ich eine einfache Funktion habe, die die Erweiterung einer Datei wiedergibt.

ext() {
  echo ${1##*.}
}

Da ich jedoch wusste, dass nichts gedruckt wird, wenn der Dateiname mit a endet ., fragte ich mich, ob das Schreiben zuverlässiger wäre:

ext() {
  extension=${1##*.}
  if [ -z "$extension" ]; then
    echo "$1"
  else
    echo "$extension"
  fi
}

Dies hängt natürlich davon ab, was Sie erreichen .möchten , aber wenn ein am Ende des Dateinamens nicht zulässig wäre, hätte ich mich überhaupt nicht gefragt.

Jorge Bucaran
quelle
Du hast eine Antwort von Michael. Zwei weitere Notizen zu Ihrem Code. Wenn Sie einen Namen example.tar.gzangeben, werden alle Suffixe ab dem ersten Punkt entfernt, wodurch nicht die einzige Erweiterung erhalten wird, die zum Aufrufen des richtigen Programms für die Verarbeitung erforderlich ist. Wenn Ihr Dateiname keine (durch Punkte getrennte) "Erweiterung (en)" hat, druckt Ihre Funktion den gesamten eingegebenen Namen. In diesem Fall benötigen Sie einen zusätzlichen Test, um eine leere Zeichenfolge zurückzugeben.
Janis
Mein Kommentar bezog sich auf allgemeine Namen mit mehr als einem Punkt oder ohne Punkte. (Wenn garantiert ist, dass alle Ihre Dateien immer nur einen Punkt haben - was eine ungewöhnliche Einschränkung ist, wenn Sie Michaels Antwort verstanden haben - und wenn Sie auch keine Punktdateien in Betracht ziehen, dh Dateien, die mit einem Punkt beginnen, ist dies möglicherweise in Ordnung. Andernfalls sollten Sie das Problem überdenken.)
Janis
1
Wenn ich meine Dateien mit vollständigen Sätzen benennen möchte, würde ich erwarten, dass viele Namen mit enden ..
Paŭlo Ebermann

Antworten:

28

Unix-Dateinamen sind nur Folgen von Bytes und können jedes Byte außer /und NULan jeder Position enthalten. Es gibt kein eingebautes Konzept für eine "Erweiterung" wie in Windows und seinen Dateisystemen, und daher gibt es keinen Grund, Dateinamen nicht mit einem Zeichen enden (oder beginnen) zu lassen, das allgemein in ihnen vorkommen kann - a .ist nichts Besonderes als ein x.

Warum erlaubt Unix Dateien mit einem Punkt am Ende des Namens? "Eine Folge von Bytes" ist eine einfache und nicht ausschließende Definition eines Namens, wenn es keinen motivierenden Grund gibt, etwas zu zählen, was es nicht gab. Eine Regel zu erstellen und anzuwenden, um etwas spezifisch auszuschließen, ist mehr Arbeit.

Gibt es eine Verwendung dafür? Wenn Sie eine Datei mit diesem Namen erstellen möchten, stellen Sie sicher. Gibt es eine Verwendung für einen Dateinamen, der mit endet x? Ich kann nicht sagen, dass ich im Allgemeinen einen Dateinamen mit einem .am Ende erstellen würde , aber beide .und xsind explizit Teil des Zeichensatzes für tragbare Dateinamen , der universell unterstützt werden muss, und keiner ist in irgendeiner Weise speziell, wenn ich also einen hätte Verwenden Sie es (vielleicht für eine mechanisch erzeugte Codierung), dann könnte ich und ich könnte mich darauf verlassen, dass es funktioniert.


Auch die besonderen Dateinamen .(dot) und ..(Punkt-Punkt), die auf die aktuellen und die übergeordneten Verzeichnisse verweisen, sind vorgeschrieben durch POSIX, und beide Ende mit einem .. Jeder Code, der sich im Allgemeinen mit Dateinamen befasst, muss diese ohnehin adressieren.

Michael Homer
quelle
3
Nitpick: "kann ein beliebiges Zeichen außer / und NUL enthalten" ist genauer "kann ein beliebiges Byte außer 0x2F und 0x00 enthalten" - der Unterschied ist wichtig, wenn jemand versucht, Dateinamen zu erstellen, die in einer Nicht-ASCII-Superset-Codierung codiert sind, was anscheinend funktioniert bis Sie über eine 0x2F oder 0x00 stolpern, die nicht alleine steht. (Allerdings müssten Sie ziemlich weit aus dem Weg gehen, um dieses Problem in der Praxis zu lösen. Keine meiner üblichen Optionen für die "umständliche Legacy-Zeichenkodierung" (Shift-JIS, Big5 und EBCDIC) kann 0x2F als verwenden Teil eines anderen Grafikzeichens als /.)
zwol
1
@zwol: Sie haben natürlich Recht mit dem Byte- / Zeichenpunkt. Ich habe das behoben. POSIX tatsächlich Mandate , dass „die Single-Byte - Codierung des <slash> Charakter benötigte die gleiche in allen Gegenden zu sein und nicht in einem Multi-Byte - Zeichen auftreten“ und Pfade nullterminierten Strings zu sein, so dass die anderen Fall nicht auftauchen. Dies bedeutet, dass beispielsweise UTF-16 keine gültige Dateisystemcodierung auf einem Unix-System ist.
Michael Homer
5

Die eigentliche Frage ist, warum Betriebssysteme in '.' ? Es gibt keinen technischen Grund dafür, es ist nur ein Standard, mit dem Sie den Dateityp ohne Überprüfung annehmen können.

Wenn Sie eine MP3-Datei in .txt umbenennen und versuchen, sie in Windows zu öffnen, werden Sie sofort erkennen, warum diese Idee Nachteile hat: Sie können die Datei plötzlich nicht mehr richtig öffnen. Technisch gesehen besteht der "beste" Weg ohne Geschwindigkeitsüberlegungen usw. wahrscheinlich darin, den Dateityp zu bestimmen, bevor entschieden wird, was damit zu tun ist, da Erweiterungen leicht gefummelt werden und Probleme verursachen können.

Der Grund, warum Linux sich nicht für einen Punkt im Namen interessiert, ist der gleiche Grund, warum eine Nicht-Computer-Person dies nicht tut: Es gibt keinen inhärenten Unterschied zwischen einem Punkt und einem anderen Zeichen außer der Tatsache, dass einige Programme zufällig codiert sind, um sie zu sehen diese Zeit und behandeln Sie es speziell.

Angenommen, Sie möchten tatsächlich nur die Erweiterung (was nicht bei beiden Snippets der Fall ist), könnten Sie Folgendes verwenden:

ext(){
    extension=
    [[ $1 =~ \. ]] && extension="${1##*.}"
    echo "$1 -> ${extension:-No extension}"
}

ext something.    # something. -> No extension
ext something.txt # something.txt -> txt
ext something     # something -> No extension
ext som.thing.mp3 # som.thing.mp3 -> mp3
ext .whatever     # .whatever -> whatever

* Beachten Sie den letzten.

Wenn Sie den Dateinamen selbst zurückgeben möchten, wenn keine Erweiterung vorhanden ist, wie dies bei Ihrem Code der Fall ist, gibt es keinen Grund, das lange zweite Snippet im SH-Stil zu verwenden. Du hast geschrieben:

ext() {
  extension=${1##*.}
  if [ -z "$extension" ]; then
    echo "$1"
  else
    echo "$extension"
  fi
}

Welches ist eigentlich nur:

ext(){
 extension="${1##*.}"
 # This line is what your first snippet is doing: 
 # echo "$extension"
 # This line is what your second snippet is doing:
 [[ $extension ]] && echo "$extension" || echo "$1"
}

Welches ist eigentlich nur:

# First snippet
ext(){
 echo "${1##*.}"
}

# Second snippet
ext(){
 extension="${1##*.}"
 echo "${extension:-$1}"
}

Sie können nichts für selbstverständlich halten, was Benutzer grundsätzlich eingeben können. Wenn Sie sehen möchten, um welche Art von Datei es sich tatsächlich handelt, versuchen Sie den Befehl file. Da das Parsen von Dateinamen, um den Dateityp herauszufinden, nicht die einzige Möglichkeit ist, diese Katze zu häuten. Sie können unter Linux sogar einen Dateinamen namens einfach haben: \

Nate
quelle
4
Was ist der Grund für die Verwendung eines \ am Ende oder eines $? Es muss keine geben, da es sich um gültige Zeichen handelt. Sie wählen "." speziell als ob es einen tatsächlichen Unterschied gibt. Das gibt es nicht.
Nate
Richtig, aber der Code echo ${1##*.}kümmert sich nur um Punkte, und wenn Punkte am Ende eines Dateinamens nicht zulässig wären, müsste ich nicht über den Sonderfall eines Zeitraums nachdenken, der einen Dateinamen beendet.
Jorge Bucaran
4
@JorgeBucaran Und wenn Ihr Code einen Dateinamen und ein anderes beliebiges Zeichen aufteilen würde, hätten Sie das gleiche Problem, wenn es am Ende wäre; Nein? Sie greifen nur zu ..
Boris die Spinne
@BoristheSpider Er "pickt .", weil die Verwendung als Trennzeichen für eine Erweiterung eine gängige Konvention ist und viele Skripte unter dieser Annahme geschrieben werden.
Barmar