2 puntos por GN⁺ 2024-06-24 | 2 comentarios | Compartir por WhatsApp
  • Cuando un usuario de Unix pone scripts personales en ~/bin/ y lo agrega al PATH, los nombres cortos de comandos pueden chocar con nuevos comandos del sistema
  • En entornos con muchos comandos disponibles, como Debian/Ubuntu, el riesgo aumenta; en una laptop Ubuntu de ejemplo se contabilizaron 21,733 comandos en /usr/bin
  • Si a los comandos personales se les antepone una coma (,), el shell y las herramientas la tratan como un carácter normal de nombre de archivo, pero al mismo tiempo permite distinguirlos fácilmente de los comandos del sistema
  • La coma puede escribirse sin usar Shift y tiene menos posibilidades de conflicto que paréntesis, barra invertida, dos puntos, acento grave, comilla simple, barra diagonal o punto, que tienen significados fuertes en el shell
  • Si presionas Tab después de ,, puedes recorrer de inmediato la lista de comandos personales, lo que facilita mantener ordenados los nombres de comandos en ~/bin/

Por qué chocan los nombres de los comandos personales

  • Muchos usuarios de Unix crean ~/bin/ en su directorio personal y lo agregan al PATH para usar comandos de conveniencia y scripts de shell propios
  • El problema es que los nombres de scripts personales suelen ser combinaciones cortas en minúsculas, así que se parecen con facilidad a los comandos básicos del sistema
  • Cuando una distribución de Linux agrega un comando nuevo, puede ocurrir que coincida por casualidad con el nombre de un comando personal ya existente
  • En entornos de la familia Debian, donde hay una gran cantidad de comandos disponibles, este problema se vuelve más real
    • En una laptop Ubuntu de ejemplo, al contar los comandos directamente bajo /usr/bin aparecen 21,733
    • apt-file search -x '^/usr/bin/[^/]*$' | wc -l

Ventajas del prefijo con coma

  • La solución es cambiar los nombres de los comandos personales a una forma que sea fácil de escribir, pero que al mismo tiempo sea poco probable como nombre de comando del sistema
  • El criterio de facilidad de escritura es no usar la tecla Shift, y aun cumpliendo esa condición no hay muchos caracteres seguros
    • Las letras minúsculas ya se usan con frecuencia en comandos del sistema
    • Los paréntesis, la barra invertida, los dos puntos, el acento grave y la comilla simple tienen significados especiales en el shell
    • La barra diagonal es un separador de directorios, así que no puede ir dentro de un nombre de archivo
    • El punto al inicio del nombre indica un archivo oculto y, en otras posiciones, también se usa mucho para separar extensiones
  • La opción que queda es la simple coma (,), y tanto las herramientas del entorno como el shell la tratan como un carácter normal dentro de un nombre de archivo
  • Si cada comando personal lleva una coma como prefijo, queda claramente diferenciado de los comandos del sistema y se vuelve más fácil evitar choques de nombres
  • Usado junto con el autocompletado con Tab, basta escribir , para ver de inmediato la lista de comandos personales
    • La lista de ejemplo incluye ,complete-scp, ,complete-ssh, ,coreoff, ,coreon, ,find, ,go-thpgp, ,gr, ,hss, ,mount-thpgp, ,mount-twt, ,range, ,svn-store-password, ,umount y otros
  • Este método se ha usado durante unos 10 años y se recomienda como una forma de mantener limpios y ordenados los nombres de comandos personales en ~/bin/

2 comentarios

 
GN⁺ 2024-06-24
Opiniones de Hacker News
  • Al ver solo el título pensé que sería una idea terrible, pero en la práctica me gusta bastante. En especial me gustó la parte de listar todas mis herramientas con Tab.
    Últimamente no he tenido muchos choques de namespaces y, la verdad, después de pasarme a un puesto de gestión, también se me aflojó un poco el instinto técnico. Siento que mi stack técnico está unos 10 años desactualizado, y me pregunto por dónde convendría empezar para volver a ponerme al día.

    • La forma interesante hoy parece ser construir algo por tu cuenta en el tiempo libre y aprender de manera natural mientras lo haces. La autosuficiencia, la creatividad y la iniciativa propia son lo que marca la pauta hoy; mientras más construyas, más motivación tendrás para resolver problemas reales y encontrar por tu cuenta soluciones modernas.
    • Yo también estoy en gestión y siento que, si no me mantengo al día, mis habilidades técnicas se van a atrofiar.
      Mi enfoque es crear herramientas que me hagan la vida más fácil. Por ejemplo, si en la empresa hay un servicio web que uso a menudo para consultas simples, reviso si tiene API y escribo una CLI para acelerar tareas cotidianas. Después de pulirla a mi gusto, la comparto con el equipo, pero convencer a otros de probarla es difícil. Aun así, como la uso todos los días, no me preocupa demasiado.
    • Por la misma razón hice un proyecto paralelo con un stack separado y más de moda, en vez del stack con el que ya estaba cómodo en el trabajo.
      El objetivo era ver nuevas perspectivas y poder conversar sobre tendencias, y parte de eso ya terminó llegando al trabajo. Además, me ayudó a entender más a fondo los componentes antiguos.
  • No termino de entender este problema. Basta con poner mi directorio bin al principio de $PATH, no al final. Para revisar mis comandos, simplemente ejecuto ls ~/bin.

    • Entonces alguna herramienta puede esperar que $0 esté en una ruta del sistema, eso se rompe y empieza una depuración frustrante.
      Al final es cuestión de elegir tu veneno.
    • ¿No basta con recordar los nombres que les puse? No entiendo por qué esto se considera una especie de hack.
    • Una de las ventajas es que puedes usar el autocompletado de fzf. Por ejemplo, en fish puedes escribir la primera letra de un comando y presionar Tab para abrir fzf.
      Así, con solo ,+Tab puedes filtrar rápidamente los comandos personalizados. En cambio, ls ~/bin requiere escribir muchas más letras para algo que haces con frecuencia, o quizá primero tengas que encontrar el autocompletado con ls+flecha arriba varias veces.
    • Escribir ls ~/bin es muchísimo más lento que escribir ,.
  • Yo uso nombres cortos de comandos personalizados como aa, st, di, dp, cm, le para wrappers delgados alrededor de git.
    Uno de ellos choca de verdad con una utilidad instalada por defecto en algún sistema. Aun así, como mi directorio bin está antes que los directorios del sistema en $PATH, el mío gana, y esa herramienta en conflicto no me interesa mucho. Si alguna otra herramienta útil para mí chocara con una de las mías, probablemente le pondría a esa otra herramienta un alias sin conflicto antes que cambiar el nombre de mi herramienta. Estas herramientas de dos letras son demasiado cómodas.

    • Este enfoque puede llevar a problemas como que apt-get upgrade ejecute Dwarf Fortress.
      https://askubuntu.com/questions/938606/dwarf-fortress-starti...
    • De acuerdo. Los nombres de 1 a 3 letras deberían reservarse para alias, funciones y scripts del usuario, y para utilidades estándar.
    • Mis alias de git suelen ser combinaciones de dos letras que empiezan con g. Por ejemplo, gs es git status.
      Pero a veces sí necesito GhostScript de verdad. Es excelente para cosas como incrustar fuentes en archivos PDF. Normalmente en esos casos uso env gs.
    • Todos mis comandos personales empiezan con j. Cuando apareció java, se puso bastante divertido. Usar una coma es una idea bastante interesante.
      Aun así, me alegra no haber empezado con k, por KDE :)
    • Es una postura algo fuerte, pero creo que los comandos del sistema no deberían ser tan fácilmente accesibles como los comandos del usuario. Debería haber algún tipo de namespace.
      Por ejemplo, creo que mkfs debería invocarse como algo tipo sys::mkfs. La línea entre comandos del sistema y comandos del usuario podría definirse de muchas maneras y habría zonas grises, pero si un usuario puede ejecutar accidentalmente un comando que ni siquiera sabía que existía y que nunca instaló explícitamente, entonces ese comando no debería estar expuesto directamente en el namespace global.
  • Hay una pregunta relacionada
    Yo uso Windows la mayor parte del tiempo y, como el autor, hice varios scripts CLI centrados en Python y los puse en el equivalente a ~/bin/. Si configuro python.exe como el programa predeterminado para la extensión .py y agrego .py a %pathext%, puedo ejecutar ~/bin/hello.py desde cualquier ruta escribiendo solo hello, y lo uso cientos de veces al día. Últimamente uso más Linux, pero todavía soy principiante y no logré hacerlo de la misma manera. En Linux no parece existir el concepto de “programa asociado”, así que no puedo simplemente invocar un archivo .py y hacer que el shell lo ejecute con Python. Claro que puedo darle chmod +x al script, pero entonces tengo que poner un shebang en el propio script, y eso me incomoda porque se siente como hardcodear. Me pregunto qué pasaría si más adelante quisiera ejecutar un script .py con /usr/bin/nohtyp en vez de /usr/bin/python. Además, tampoco encontré una forma de omitir la parte .py al invocar el script. No intento criticar el diseño de Linux, y sé que tiene muchas ventajas, pero de verdad quiero ejecutar como hello un hello.py que está en $PATH

    • En Linux sigo pensando que el shebang es la herramienta adecuada para este problema. Para algo simple, puedes poner un enlace simbólico my_python en alguna ruta y usar /usr/bin/env my_python como shebang
      Si quieres un enfoque más principista, mira la herramienta update-alternatives. Ofrece este tipo de abstracción de forma más general: https://linuxconfig.org/how-to-set-default-programs-using-up...
    • Otros ya mencionaron las soluciones, pero quiero agregar una razón de por qué es así
      En Linux —y, de hecho, en la mayoría de las plataformas fuera de Windows— el significado de las extensiones de archivo es mucho más débil. La posibilidad de ejecutar cualquier tipo de archivo ejecutable no la determina la extensión, sino cosas como el flag +x. Gracias a eso, puedes reescribirlo cambiando el lenguaje de implementación sin romper a quien lo invoca. La extensión .py solo tiene sentido para módulos que se importan y usan; si es un script que se ejecuta, basta con mirar el shebang cuando sea necesario. Los scripts distribuidos externamente suelen usar #!/usr/bin/env python, y los scripts incluidos en paquetes de una distribución se suelen sobrescribir con algo como #!/usr/bin/python. Además, el shebang no admite varios argumentos, pero GNU env admite el argumento -S, que puede imitarlo. Aun así, queda el problema de la longitud de los argumentos
    • Simplemente quítale .py al nombre del archivo. Llamarlo "hello" está perfectamente bien
      No se me ocurren muchas desventajas del shebang. Si de verdad quieres ejecutarlo con otro intérprete, puedes hacerlo explícito, como "nohtyp hello". Si aun así te molesta demasiado, puedes definir un alias en el archivo de inicio del shell. Por ejemplo, en bash podrías hacer alias hello="python3 /path/to/hello.py". Si quisieras, incluso podrías escribir un script corto que genere automáticamente estos alias para el contenido de un directorio determinado
    • Ese concepto sí existe, pero no dentro de la sintaxis del shell. Normalmente es un asunto a nivel de aplicación delegado al escritorio/GUI
      En scripts de shell, lo usual es agregar un shebang y hacer ejecutable el archivo, declarando el ejecutable dentro del propio script. Puedes pensar en el shebang como una especie de extensión de archivo. Si después de chmod +x ./malware.py no funciona ./malware.py, revisa la ruta a la que apunta el shebang. Si el intérprete puede ejecutar el script como un argumento normal, también podrías lograr algo parecido con xdg-open malware.py. Sería lo mismo que hacer doble clic en el administrador de archivos predeterminado. Cuando usaba Linux como sistema operativo principal de escritorio, tenía un alias llamado xop, pero lo usaba solo para archivos de datos como imágenes o documentos, donde el comportamiento predeterminado ya era el correcto. No recomiendo configurar el programa predeterminado de los scripts ejecutables como el intérprete. Quizás por defecto quieras abrir el script en un editor, no ejecutarlo. Creo que xdg-open es una herramienta del entorno Gnome, pero eso no significa que no pueda usarse en otros escritorios; yo también la usé en Xubuntu. Si de verdad quieres que todos los archivos Python se ejecuten por defecto incluso en contexto GUI, se puede configurar ese valor predeterminado, pero man xdg-open puede ayudar. De nuevo: no es un buen consejo
    • No logra directamente el objetivo, pero el shebang solo está hardcodeado a medias. La forma “correcta” de usar shebang —aunque hay algunas advertencias, como se ve en https://unix.stackexchange.com/a/29620— es #!/usr/bin/env python
      Así se ejecuta el primer python que se encuentre en la ruta. Si más adelante quieres ejecutarlo con /usr/bin/nohtyp en vez de /usr/bin/python, puedes crear un enlace simbólico llamado python que apunte a /usr/bin/nohtyp en un directorio que se busque antes que /usr/bin. Por ejemplo, puedes agregar ~/myCommandPreferences al inicio de $PATH
  • Otra forma de evitar conflictos en $PATH es crear nombres de ejecutables muy largos, con poca probabilidad de que los use otro ejecutable, y poner alias cortos en bashrc
    Los alias no afectan a los ejecutables invocados dentro de los scripts, y en mis scripts puedo seguir refiriéndome a ellos por el nombre largo. La desventaja es que no se obtiene el mismo nivel de usabilidad con autocompletado por tabulación, y esa parte sí es muy buena. Además, todavía puede haber conflictos con scripts que deben ejecutarse con source y no como subprocesos, como los scripts de activación de venv de Python, pero esos casos son raros

    • En zsh, ese autocompletado también funciona
  • Empezar con coma es una técnica común también en las comunidades de expansores de texto/sustitución de texto

    • Así es. La mayoría de mis alias de vim también empiezan con ,
  • Hace poco revisé ~/.local/bin/ y descubrí decenas de ejecutables que no recordaba haber puesto ahí
    La mayoría estaban relacionados con pyside, pero también había otros scripts. Tuve que abrirlos uno por uno para recordar cuáles había escrito yo y cuáles eran de otros. Si los nombres de mis scripts hubieran empezado con coma, habría sido mucho más rápido, y también me habría ayudado a recordar para qué había creado cada script antes de abrirlo

    • Normalmente ~/.local/bin/ se usa para scripts instalados, y lo que escribes localmente tú mismo va en ~/bin/
  • Paso. Basta con poner mi bin personal al inicio de $PATH y usar /usr/bin o /bin cuando quiera hacer referencia a un programa que quedó oculto
    La lista de herramientas personalizadas se puede ver con ~/bin/[Tab]

    • No entiendo por qué tendría que seguir recordando la coma, si no quiero usar el mismo nombre mientras hago que mis propias versiones oculten utilidades del sistema
      Si no me gusta el grep del sistema, por ejemplo el grep de Solaris, y quiero usar mi grep de GNU preferido, ¿por qué no simplemente dejarlo como grep?
  • Haber conocido esta idea hace 5 años me permitió poner orden en mi colección de trucos de shell. Entre alias y ~/bin, tengo más de 50 comandos con coma, y mi vida en la shell es mucho más fluida que antes, cuando todo estaba mezclado

  • También se discutió en 2020: https://news.ycombinator.com/item?id=22778988 (90 comentarios)

 
kayws426 2024-06-24

¿Qué tal usar '_'?