Estoy intentando escribir una función de shell bash que me permita eliminar copias duplicadas de directorios de mi variable de entorno PATH.
Me dijeron que es posible lograr esto con un comando de una línea usando el awk
comando, pero no sé cómo hacerlo. ¿Alguien sabe cómo?
Respuesta1
Si aún no tiene duplicados en PATH
y solo desea agregar directorios si aún no están allí, puede hacerlo fácilmente solo con el shell.
for x in /path/to/add …; do
case ":$PATH:" in
*":$x:"*) :;; # already there
*) PATH="$x:$PATH";;
esac
done
Y aquí hay un fragmento de shell que elimina duplicados de $PATH
. Revisa las entradas una por una y copia las que aún no se han visto.
if [ -n "$PATH" ]; then
old_PATH=$PATH:; PATH=
while [ -n "$old_PATH" ]; do
x=${old_PATH%%:*} # the first remaining entry
case $PATH: in
*:"$x":*) ;; # already there
*) PATH=$PATH:$x;; # not there yet
esac
old_PATH=${old_PATH#*:}
done
PATH=${PATH#:}
unset old_PATH x
fi
Respuesta2
Aquí hay uninteligibleSolución de una sola línea que hace todo lo correcto: elimina duplicados, conserva el orden de las rutas y no agrega dos puntos al final. Por lo tanto, debería proporcionarle una RUTA deduplicada que ofrezca exactamente el mismo comportamiento que la original:
PATH="$(perl -e 'print join(":", grep { not $seen{$_}++ } split(/:/, $ENV{PATH}))')"
Simplemente se divide en dos puntos ( split(/:/, $ENV{PATH})
), utiliza usos grep { not $seen{$_}++ }
para filtrar cualquier instancia repetida de rutas, excepto la primera aparición, y luego vuelve a unir las restantes separadas por dos puntos e imprime el resultado ( print join(":", ...)
).
Si desea más estructura a su alrededor, así como la capacidad de deduplicar otras variables, pruebe este fragmento, que estoy usando actualmente en mi propia configuración:
# Deduplicate path variables
get_var () {
eval 'printf "%s\n" "${'"$1"'}"'
}
set_var () {
eval "$1=\"\$2\""
}
dedup_pathvar () {
pathvar_name="$1"
pathvar_value="$(get_var "$pathvar_name")"
deduped_path="$(perl -e 'print join(":",grep { not $seen{$_}++ } split(/:/, $ARGV[0]))' "$pathvar_value")"
set_var "$pathvar_name" "$deduped_path"
}
dedup_pathvar PATH
dedup_pathvar MANPATH
Ese código deduplicará tanto PATH como MANPATH, y puede invocar fácilmente dedup_pathvar
otras variables que contienen listas de rutas separadas por dos puntos (por ejemplo, PYTHONPATH).
Respuesta3
Aquí hay uno elegante:
printf %s "$PATH" | awk -v RS=: -v ORS=: '!arr[$0]++'
Más largo (para ver cómo funciona):
printf %s "$PATH" | awk -v RS=: -v ORS=: '{ if (!arr[$0]++) { print $0 } }'
Ok, ya que eres nuevo en Linux, aquí te explicamos cómo configurar la RUTA sin un ":" final.
PATH=`printf %s "$PATH" | awk -v RS=: '{ if (!arr[$0]++) {printf("%s%s",!ln++?"":":",$0)}}'`
Por cierto, asegúrese de NO tener directorios que contengan ":" en su RUTA; de lo contrario, se estropeará.
algún crédito a:
Respuesta4
Siempre que agreguemos líneas que no sean awk:
PATH=$(zsh -fc "typeset -TU P=$PATH p; echo \$P")
(Podría ser tan simple como PATH=$(zsh -fc 'typeset -U path; echo $PATH')
zsh siempre lee al menos un zshenv
archivo de configuración, que puede modificarse PATH
).
Utiliza dos características interesantes de zsh:
- escalares ligados a matrices (
typeset -T
) - y matrices que eliminan automáticamente valores duplicados (
typeset -U
).