2 Punkte von GN⁺ 2024-06-24 | 2 Kommentare | Auf WhatsApp teilen
  • Wenn Unix-Nutzer persönliche Skripte in ~/bin/ ablegen und zu PATH hinzufügen, können kurze Befehlsnamen mit neuen Systembefehlen kollidieren
  • In Umgebungen mit vielen bereitgestellten Befehlen wie Debian/Ubuntu ist das Risiko noch größer; auf einem Beispiel-Ubuntu-Laptop wurden 21.733 Befehle in /usr/bin gezählt
  • Wenn man persönlichen Befehlen ein Komma (,) voranstellt, behandeln Shell und Werkzeuge es als normales Dateinamenzeichen, während es sich zugleich leicht von Systembefehlen unterscheiden lässt
  • Das Komma kann ohne Shift eingegeben werden und birgt weniger Konfliktpotenzial als Klammern, Backslash, Doppelpunkt, Backtick, einfaches Anführungszeichen, Slash oder Punkt, die in der Shell eine starke Bedeutung haben
  • Drückt man nach , die Tab-Taste, kann man die Liste persönlicher Befehle sofort durchgehen, was es erleichtert, Befehlsnamen in ~/bin/ sauber zu halten

Warum persönliche Befehlsnamen kollidieren

  • Viele Unix-Nutzer erstellen in ihrem Home-Verzeichnis ein ~/bin/ und fügen es zu PATH hinzu, um persönliche Komfortbefehle und Shell-Skripte zu verwenden
  • Das Problem ist, dass persönliche Skriptnamen meist aus kurzen Kombinationen aus Kleinbuchstaben bestehen und damit leicht Systembefehlen ähneln
  • Wenn Linux-Distributionen neue Befehle hinzufügen, kann ein vorhandener persönlicher Befehl zufällig denselben Namen bekommen
  • In Debian-basierten Umgebungen mit ihrer großen Zahl bereitgestellter Befehle wird dieses Problem besonders realistisch
    • Zählt man auf einem Beispiel-Ubuntu-Laptop die Befehle direkt unter /usr/bin, kommt man auf 21.733
    • apt-file search -x '^/usr/bin/[^/]*$' | wc -l

Die Vorteile des Komma-Präfixes

  • Die Lösung besteht darin, persönliche Befehlsnamen so zu verändern, dass sie leicht einzugeben sind, aber kaum als Systembefehlsnamen gewählt werden
  • Das Kriterium für gute Eingabefreundlichkeit ist, die Shift-Taste nicht benutzen zu müssen; unter dieser Bedingung gibt es nicht viele sichere Zeichen
    • Kleinbuchstaben werden bereits häufig in Systembefehlen verwendet
    • Klammern, Backslash, Doppelpunkt, Backtick und einfaches Anführungszeichen haben in der Shell eine besondere Bedeutung
    • Der Slash ist ein Verzeichnistrenner und kann nicht in Dateinamen vorkommen
    • Der Punkt steht am Anfang eines Dateinamens für eine versteckte Datei und wird auch sonst oft zur Trennung von Erweiterungen verwendet
  • Die verbleibende einfache Wahl ist das Komma (,), und die umliegenden Werkzeuge sowie die Shell behandeln das Komma als normales Zeichen in Dateinamen
  • Wenn man jedem persönlichen Befehl ein Komma voranstellt, lässt er sich klar von Systembefehlen unterscheiden, sodass Namenskollisionen leichter vermieden werden können
  • In Verbindung mit Tab-Vervollständigung kann man nach Eingabe von , sofort die Liste persönlicher Befehle prüfen
    • Die Beispiel-Liste enthält ,complete-scp, ,complete-ssh, ,coreoff, ,coreon, ,find, ,go-thpgp, ,gr, ,hss, ,mount-thpgp, ,mount-twt, ,range, ,svn-store-password, ,umount und weitere
  • Dieser Ansatz wird seit etwa 10 Jahren verwendet und wird als Methode empfohlen, persönliche Befehlsnamen in ~/bin/ sauber und ordentlich zu halten

2 Kommentare

 
GN⁺ 2024-06-24
Meinungen auf Hacker News
  • Nur vom Titel her dachte ich, das sei eine schreckliche Idee, aber tatsächlich gefällt sie mir ziemlich gut. Besonders mochte ich den Teil, in dem per Tab alle meine Tools aufgelistet werden.
    In letzter Zeit hatte ich nicht viele Namespace-Kollisionen, und es stimmt auch, dass mein technisches Gespür etwas nachgelassen hat, seit ich ins Management gewechselt bin. Mein Tech-Stack fühlt sich etwa 10 Jahre veraltet an; ich frage mich, wo ich anfangen sollte, um wieder auf den aktuellen Stand zu kommen.

    • Die coole Art heutzutage scheint zu sein, in der Freizeit selbst etwas zu bauen und dabei ganz natürlich zu lernen. Selbstversorgung, Kreativität und Eigeninitiative sind der heutige Zeitgeist; je mehr man baut, desto mehr bekommt man ein Gefühl dafür, echte Probleme zu lösen, und desto mehr Motivation entsteht, moderne Lösungen selbst zu finden.
    • Ich bin auch im Management und habe das Gefühl, dass meine technischen Fähigkeiten verkümmern, wenn ich nicht dranbleibe.
      Meine Methode ist, selbst Tools zu bauen, die mir das Leben erleichtern. Wenn es zum Beispiel in der Firma einen Webservice gibt, den ich oft für einfache Abfragen nutze, schaue ich, ob es eine API gibt, und schreibe eine CLI, um Alltagsaufgaben schneller zu erledigen. Nachdem ich sie so poliert habe, dass sie mir gefällt, teile ich sie mit dem Team, aber andere davon zu überzeugen, sie auszuprobieren, ist schwierig. Da ich sie aber jeden Tag selbst nutze, kümmert mich das nicht besonders.
    • Aus demselben Grund habe ich ein Side Project mit einem separaten, stärker im Trend liegenden Stack gebaut, statt mit dem Stack, den ich aus der Arbeit gewohnt bin.
      Ziel war, neue Perspektiven zu sehen und über Trends mitreden zu können; ein Teil davon ist inzwischen auch in die Arbeit eingeflossen. Dadurch habe ich auch ein tieferes Verständnis für die älteren Komponenten bekommen.
  • Ich verstehe dieses Problem nicht so recht. Man muss sein bin-Verzeichnis einfach an den Anfang von $PATH setzen, nicht ans Ende. Um meine Befehle durchzusehen, führe ich einfach ls ~/bin aus.

    • Dann kann es passieren, dass irgendein Tool erwartet, dass $0 in einem Systempfad liegt, das kaputtgeht und eine frustrierende Debugging-Session beginnt.
      Am Ende ist es die Frage, welches Gift man wählt.
    • Kann man sich nicht einfach die Namen merken, die man vergeben hat? Ich verstehe nicht, warum das als eine Art Hack gilt.
    • Einer der Vorteile ist, dass man die fzf-Autovervollständigung nutzen kann. In fish kann man zum Beispiel den ersten Buchstaben eines Befehls tippen und Tab drücken, um fzf zu öffnen.
      Dann kann man mit ,+Tab benutzerdefinierte Befehle schnell herausfiltern. ls ~/bin dagegen erfordert für etwas, das man häufig tut, ziemlich viele Tastendrücke; oder man muss vielleicht erst mit ls+mehrfach Pfeil nach oben die Autovervollständigung finden.
    • ls ~/bin ist beim Tippen viel langsamer als ,.
  • Für dünne Wrapper um git verwende ich kurze benutzerdefinierte Befehlsnamen wie aa, st, di, dp, cm, le.
    Einer davon kollidiert tatsächlich mit einem Utility, das auf manchen Systemen standardmäßig installiert ist. Aber mein bin-Verzeichnis steht in $PATH vor den Systemverzeichnissen, also gewinnt meins, und das kollidierende Tool interessiert mich nicht besonders. Wenn ein anderes für mich nützliches Tool mit meinem Tool kollidieren würde, würde ich diesem anderen Tool wahrscheinlich eher einen kollisionsfreien Alias geben, als mein eigenes Tool umzubenennen. Diese Zwei-Buchstaben-Tools sind einfach zu bequem.

    • So eine Vorgehensweise kann zu Problemen führen, bei denen apt-get upgrade plötzlich Dwarf Fortress startet.
      https://askubuntu.com/questions/938606/dwarf-fortress-starti...
    • Genau. Namen mit 1 bis 3 Zeichen sollten für Benutzer-Aliasse, Funktionen, Skripte und Standard-Utilities freigehalten werden.
    • Meine git-Aliasse sind meistens Zwei-Buchstaben-Kombinationen, die mit g beginnen. Zum Beispiel ist gs git status.
      Aber manchmal brauche ich tatsächlich GhostScript. Für Dinge wie das Einbetten von Schriften in PDF-Dateien ist es hervorragend. Normalerweise verwende ich dann env gs.
    • Meine persönlichen Befehle beginnen alle mit j. Als java auftauchte, wurde das ziemlich unterhaltsam. Ein Komma zu verwenden ist eine ziemlich interessante Idee.
      Trotzdem bin ich froh, dass ich nicht mit k angefangen habe, wegen KDE :)
    • Eine etwas starke Meinung, aber ich finde, Systembefehle sollten nicht genauso leicht zugänglich sein wie Benutzerbefehle. Es sollte irgendeine Form von Namespace geben.
      Zum Beispiel sollte mkfs meiner Meinung nach als sys::mkfs oder ähnlich aufgerufen werden. Die Grenze zwischen Systembefehlen und Benutzerbefehlen kann auf verschiedene Arten gezogen werden und es wird Grauzonen geben, aber wenn ein Nutzer einen Befehl versehentlich ausführen kann, von dem er nicht einmal weiß, dass er existiert, und den er nie ausdrücklich installiert hat, dann sollte dieser Befehl nicht direkt im globalen Namespace sichtbar sein.
  • Dazu gibt es eine verwandte Frage
    Ich nutze überwiegend Windows und habe, ähnlich wie der Autor, mehrere Python-zentrierte CLI-Skripte erstellt und sie an einem Ort abgelegt, der ~/bin/ entspricht. Wenn man python.exe als Standardprogramm für die Erweiterung .py festlegt und .py zu %pathext% hinzufügt, kann man von jedem Pfad aus einfach hello eingeben, um ~/bin/hello.py auszuführen; ich nutze das hunderte Male am Tag. Inzwischen verwende ich öfter Linux, bin dort aber noch Anfänger und habe es nicht geschafft, dasselbe Muster nachzubauen. Unter Linux scheint es kein Konzept eines „zugeordneten Programms“ zu geben, sodass man eine .py-Datei nicht einfach aufrufen und die Shell sie mit Python ausführen lassen kann. Natürlich kann man dem Skript chmod +x geben, aber dann muss man in das Skript selbst einen Shebang einfügen, was sich unangenehm nach Hardcoding anfühlt. Was, wenn ich später ein .py-Skript nicht mit /usr/bin/python, sondern mit /usr/bin/nohtyp ausführen möchte? Außerdem habe ich auch keinen Weg gefunden, beim Aufruf des Skripts den .py-Teil wegzulassen. Ich will das Linux-Design nicht kritisieren und weiß, dass es viele Vorteile hat, aber ich möchte wirklich hello.py aus dem $PATH als hello ausführen

    • Unter Linux ist der Shebang für dieses Problem meiner Meinung nach immer noch das passende Werkzeug. Wenn du es leichtgewichtig halten willst, leg irgendwo in deinem Pfad einen symbolischen Link my_python an und schreibe den Shebang als /usr/bin/env my_python
      Wenn du einen prinzipielleren Ansatz willst, schau dir das Tool update-alternatives an. Es bietet solche Abstraktionen allgemeiner an: https://linuxconfig.org/how-to-set-default-programs-using-up...
    • Die Lösung haben andere schon genannt, aber ich möchte noch einen Grund ergänzen, warum das so ist
      Unter Linux, und eigentlich auf den meisten Plattformen außer Windows, haben Dateiendungen eine deutlich schwächere Bedeutung. Ob eine Datei ausführbar ist, wird bei jeder Art von ausführbarer Datei nicht durch die Endung bestimmt, sondern etwa durch das +x-Flag. Dadurch kann man die Implementierungssprache ändern und den Aufrufer unverändert lassen. Die Endung .py ist vor allem für Module sinnvoll, die importiert und verwendet werden; bei einem ausführbaren Skript schaut man bei Bedarf auf den Shebang. Extern verteilte Skripte verwenden normalerweise #!/usr/bin/env python, während Skripte in Distributionspaketen etwa mit #!/usr/bin/python überschrieben werden. Außerdem unterstützt der Shebang zwar keine mehreren Argumente, aber GNU env bietet das Argument -S, mit dem man das nachbilden kann. Das Problem der Argumentlänge bleibt allerdings bestehen
    • Lass im Dateinamen einfach .py weg. Es ist völlig in Ordnung, sie "hello" zu nennen
      Mir fallen nicht wirklich Nachteile des Shebangs ein. Wenn du es wirklich mit einem anderen Interpreter ausführen willst, kannst du das explizit tun, etwa mit "nohtyp hello". Wenn dich das trotzdem zu sehr stört, kannst du in deinen Shell-Startdateien Aliasse definieren. In bash ginge zum Beispiel alias hello="python3 /path/to/hello.py". Wenn du willst, kannst du sogar ein kurzes Skript schreiben, das solche Aliasse automatisch für den Inhalt eines bestimmten Verzeichnisses erzeugt
    • So ein Konzept gibt es zwar, aber es gehört nicht zur Shell-Syntax. Normalerweise ist das ein Problem auf Anwendungsebene, das an Desktop/GUI delegiert wird
      In Shell-Skripten fügt man üblicherweise einen Shebang hinzu und macht die Datei ausführbar, wodurch das ausführbare Programm im Skript selbst deklariert wird. Man kann sich den Shebang als eine Art Dateiendung vorstellen. Wenn nach chmod +x ./malware.py ein ./malware.py nicht funktioniert, sollte man den Pfad prüfen, auf den der Shebang zeigt. Wenn der Interpreter ein Skript als normales Argument ausführen kann, lässt sich mit etwas wie xdg-open malware.py ein ähnliches Verhalten erzeugen. Das entspräche dem Doppelklick im Standard-Dateimanager. Als ich Linux als primäres Desktop-Betriebssystem genutzt habe, hatte ich einen Alias namens xop, aber ich habe ihn nur für Datendateien wie Bilder oder Dokumente verwendet, bei denen das Standardverhalten ohnehin passte. Das Standardprogramm für ausführbare Skripte auf den Interpreter zu setzen, würde ich nicht empfehlen. Standardmäßig möchte man Skripte vielleicht lieber in einem Editor öffnen, statt sie auszuführen. Ich halte xdg-open für ein Tool aus der Gnome-Ecke, was aber nicht heißt, dass es auf anderen Desktops nicht nutzbar wäre; ich habe es auch unter Xubuntu verwendet. Wenn du wirklich alle Python-Dateien auch im GUI-Kontext standardmäßig ausführen willst, kannst du so eine Voreinstellung setzen, aber man xdg-open könnte helfen. Noch einmal: Das ist kein guter Rat
    • Es erreicht dein Ziel nicht direkt, aber ein Shebang ist nur halb hardcodiert. Die „richtige“ Art, einen Shebang zu verwenden, ist, abgesehen von einigen Fallstricken siehe https://unix.stackexchange.com/a/29620, #!/usr/bin/env python
      Dadurch wird das erste python ausgeführt, das im Pfad gefunden wird. Wenn du später nicht /usr/bin/python, sondern /usr/bin/nohtyp ausführen willst, kannst du in einem Verzeichnis, das vor /usr/bin durchsucht wird, einen symbolischen Link python anlegen, der auf /usr/bin/nohtyp zeigt. Zum Beispiel könntest du ~/myCommandPreferences an den Anfang von $PATH setzen
  • Eine andere Möglichkeit, Konflikte im $PATH zu vermeiden, ist, ausführbaren Dateien sehr lange Namen zu geben, die andere ausführbare Dateien kaum verwenden werden, und in der bashrc kurze Aliasse dafür anzulegen
    Aliasse wirken sich nicht auf ausführbare Dateien aus, die innerhalb von Skripten aufgerufen werden, und in meinen Skripten kann ich weiterhin die langen Namen referenzieren. Der Nachteil ist, dass man nicht dieselbe Nutzbarkeit der Tab-Vervollständigung bekommt, und genau die ist wirklich ziemlich gut. Außerdem kann es bei Skripten, die wie das Aktivierungsskript von Pythons venv nicht als Unterprozess ausgeführt, sondern sourced werden müssen, weiterhin zu Konflikten kommen, aber solche Fälle sind selten

    • In zsh funktioniert auch diese Vervollständigung
  • Die Methode, mit einem Komma zu beginnen, ist auch in der Community rund um Texterweiterungen/Textsubstitution eine verbreitete Technik

    • Stimmt. Die meisten meiner vim-Aliasse beginnen ebenfalls mit ,
  • Neulich habe ich in ~/.local/bin/ nachgesehen und festgestellt, dass dort Dutzende ausführbarer Dateien liegen, an deren Ablage ich mich nicht erinnern konnte
    Die meisten waren pyside-bezogen, aber es gab auch andere Skripte. Ich musste sie einzeln öffnen, um mich daran zu erinnern, welche ich selbst geschrieben hatte und welche von anderen stammten. Wenn die Namen meiner Skripte mit einem Komma begonnen hätten, wäre das viel schneller gegangen, und es hätte mir auch geholfen, mich schon vor dem Öffnen daran zu erinnern, warum ich das jeweilige Skript erstellt hatte

    • Üblicherweise ist ~/.local/bin/ für installierte Skripte gedacht; lokal selbst geschriebene legt man in ~/bin/ ab
  • Ich verzichte. Man kann sein persönliches bin an den Anfang von $PATH setzen und für verdeckte Programme /usr/bin oder /bin verwenden.
    Die Liste der personalisierten Tools lässt sich mit ~/bin/[Tab] anzeigen.

    • Ich verstehe nicht, warum ich mir ständig das Komma merken sollte, wenn ich zwar System-Utilities mit meinen eigenen überdecken, aber nicht denselben Namen verwenden will.
      Wenn mir das grep des Systems, etwa Solaris-grep, nicht gefällt und ich lieber mein bevorzugtes GNU-grep verwenden möchte, warum sollte ich es dann nicht einfach grep nennen?
  • Dass ich vor fünf Jahren auf diese Idee gestoßen bin, hat Ordnung in meine Sammlung von Shell-Tricks gebracht. Zusammen mit Aliassen und ~/bin habe ich über 50 Komma-Befehle, und mein Shell-Alltag läuft deutlich reibungsloser als in dem früheren Durcheinander.

  • Wurde auch 2020 diskutiert: https://news.ycombinator.com/item?id=22778988 (90 Kommentare)

 
kayws426 2024-06-24

Wie wäre es mit der Verwendung von '_'?