¡Mirad! La función de 12 líneas de fuerza industrial ... técnicamente bash y zsh-portable que adora tu script de inicio ~/.bashrc
o ~/.zshrc
de elección:
# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
# For each passed dirname...
local dirname
for dirname; do
# Strip the trailing directory separator if any from this dirname,
# reducing this dirname to the canonical form expected by the
# test for uniqueness performed below.
dirname="${dirname%/}"
# If this dirname is either relative, duplicate, or nonextant, then
# silently ignore this dirname and continue to the next. Note that the
# extancy test is the least performant test and hence deferred.
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
# Else, this is an existing absolute unique dirname. In this case,
# append this dirname to the current ${PATH}.
PATH="${PATH}:${dirname}"
done
# Strip an erroneously leading delimiter from the current ${PATH} if any,
# a common edge case when the initial ${PATH} is the empty string.
PATH="${PATH#:}"
# Export the current ${PATH} to subprocesses. Although system-wide scripts
# already export the ${PATH} by default on most systems, "Bother free is
# the way to be."
export PATH
}
Prepárate para la gloria instantánea. Entonces, en lugar de hacer esto y deseando lo mejor:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Haga esto en su lugar y tenga la garantía de obtener lo mejor, ya sea que realmente quiera eso o no:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
Muy bien, defina "Mejor".
Anexar y anteponer con seguridad a la corriente ${PATH}
no es el asunto trivial que comúnmente se supone que es. Si bien son convenientes y aparentemente razonables, las frases ingeniosas del formulario export PATH=$PATH:~/opt/bin
invitan a complicaciones diabólicas con:
Nombres de directorio relativos accidentalmente (por ejemplo, export PATH=$PATH:opt/bin
). Si bien bash
y en zsh
silencio aceptan e ignoran en su mayoría los nombres de directorios relativos en la mayoría de los casos, los nombres de directorios relativos con el prefijo uno h
o t
(y posiblemente otros caracteres nefastos) hacen que ambos se mutilen vergonzosamente por Harakiri, la obra maestra seminal de 1962 de Masaki Kobayashi :
# Don't try this at home. You will feel great pain.
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
/usr/local/bin:/usr/bin:arakiri
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
binanuki/yokai # Congratulations. Your system is now face-up in the gutter.
Accidentalmente nombres de directorio duplicados. Si bien los ${PATH}
nombres de directorio duplicados son en gran medida inocuos, también son indeseados, engorrosos, ligeramente ineficientes, impiden la depuración y promueven el desgaste de la unidad, como esta respuesta. Mientras que los SSD de estilo NAND son ( por supuesto ) inmunes al desgaste de lectura, los HDD no lo son. El acceso innecesario al sistema de archivos en cada intento de comando implica un desgaste innecesario del cabezal de lectura al mismo tempo. Los duplicados son particularmente untuosos cuando se invocan proyectiles anidados en subprocesos anidados, momento en el cual las frases ingenuas aparentemente inocuas export PATH=$PATH:~/wat
explotan rápidamente en el Séptimo Círculo del ${PATH}
Infierno PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Solo Beelzebubba puede ayudarlo si luego agrega nombres de directorio adicionales. (No dejes que esto le pase a tus preciosos hijos. )
- Nombres de directorio que faltan accidentalmente. Una vez más, si bien los
${PATH}
nombres de directorio faltantes son en gran medida inocuos, también suelen ser no deseados, engorrosos, ligeramente ineficientes, impiden la depuración y promueven el desgaste de la unidad.
Ergo, automatización amigable como la función de shell definida anteriormente. Debemos salvarnos de nosotros mismos.
Pero ... ¿Por qué "+ path.append ()"? ¿Por qué no simplemente append_path ()?
Para de desambiguación (por ejemplo, con comandos externos en las actuales ${PATH}
funciones de shell o del sistema definida en otra parte), funciones de shell definidos por el usuario son idealmente el prefijo o sufijo única subseries soportados por bash
y zsh
pero prohibidos de otro modo para nombres base comando estándar - como, por ejemplo, +
.
Oye. Funciona. No me juzgues
Pero ... ¿Por qué "+ path.append ()"? ¿Por qué no "+ path.prepend ()"?
Debido a que agregar a la corriente ${PATH}
es más seguro que anteponer a la corriente ${PATH}
, todas las cosas son iguales, lo que nunca son. Anular comandos de todo el sistema con comandos específicos del usuario puede ser insalubre en el mejor de los casos y loco en el peor En Linux, por ejemplo, las aplicaciones posteriores comúnmente esperan las variantes de comandos GNU coreutils en lugar de las derivadas o alternativas no estándar personalizadas.
Dicho esto, absolutamente hay casos de uso válidos para hacerlo. Definir la +path.prepend()
función equivalente es trivial. Sans prolix nebulosity, por su cordura compartida:
+path.prepend() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
PATH="${dirname}:${PATH}"
done
PATH="${PATH%:}"
export PATH
}
Pero ... ¿por qué no Gilles?
La respuesta aceptada de Gilles en otra parte es impresionantemente óptima en el caso general como un "agregado idempotente agnóstico de caparazón" . En el caso común de bash
y zsh
con no hay enlaces simbólicos indeseables, sin embargo, la penalización de rendimiento requerido para ello entristece la arrocera de Gentoo en mí. Incluso en presencia de enlaces simbólicos indeseables, es discutible si la bifurcación de un subshell por add_to_PATH()
argumento vale la inserción potencial de duplicados de enlaces simbólicos.
Para casos de uso estrictos que exigen que se eliminen incluso los duplicados de enlaces simbólicos, esta zsh
variante específica lo hace a través de builtins eficientes en lugar de tenedores ineficientes:
+path.append() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname:A}:"* &&
-d "${dirname}" ]] || continue
PATH="${PATH}:${dirname}"
done
PATH="${PATH#:}"
export PATH
}
Tenga en cuenta el *":${dirname:A}:"*
más que *":${dirname}:"*
el original. :A
es un zsh
ismos maravilloso tristemente ausente debajo de la mayoría de los otros caparazones, incluido bash
. Para citar man zshexpn
:
R : Convierta un nombre de archivo en una ruta absoluta como lo hace el a
modificador, y luego pase el resultado a través de la realpath(3)
función de biblioteca para resolver enlaces simbólicos. Nota: en los sistemas que no tienen una realpath(3)
función de biblioteca, enlaces simbólicos no se resuelven, por lo que en esos sistemas a
, y A
son equivalentes.
No más preguntas.
De nada. Disfruta del bombardeo seguro. Ahora te lo mereces.