bash - ruta - obtener nombre de archivo shell
Detecta si la ruta del usuario tiene un directorio específico en ella (7)
Con /bin/bash
, ¿cómo detectaría si un usuario tiene un directorio específico en su variable $ PATH?
Por ejemplo
if [ -p "$HOME/bin" ]; then
echo "Your path is missing ~/bin, you might want to add it."
else
echo "Your path is correctly set"
fi
Algo realmente simple e ingenuo
echo "$PATH"|grep -q whatever && echo "found it"
Donde sea lo que sea que estés buscando. En lugar de &&
puedes poner $?
en una variable o use una declaración if
adecuada.
Las limitaciones incluyen:
- Lo anterior coincidirá con subcadenas de rutas más grandes (intente con la coincidencia en "bin" y probablemente la encuentre, a pesar de que "bin" no está en su ruta, / bin y / usr / bin son)
- Lo anterior no expandirá automáticamente accesos directos como ~
O usando un perl de una sola línea:
perl -e ''exit(!(grep(m{^/usr/bin$},split(":", $ENV{PATH}))) > 0)'' && echo "found it"
Eso todavía tiene la limitación de que no hará expansiones de shell, pero no falla si una subcadena coincide. (Lo anterior coincide con " /usr/bin
", en caso de que no fuera claro).
Escribí la siguiente función de shell para informar si un directorio figura en la PATH
actual. Esta función es compatible con POSIX y se ejecutará en shells compatibles como Dash y Bash (sin depender de las funciones específicas de Bash).
Incluye funcionalidad para convertir una ruta relativa a una ruta absoluta. Utiliza las utilidades readlink
o realpath
para esto, pero estas herramientas no son necesarias si el directorio proporcionado no tiene ..
u otros enlaces como componentes de su ruta. Aparte de esto, la función no requiere ningún programa externo al shell.
# Check that the specified directory exists – and is in the PATH.
is_dir_in_path()
{
if [ -z "${1:-}" ]; then
printf "The path to a directory must be provided as an argument./n" >&2
return 1
fi
# Check that the specified path is a directory that exists.
if ! [ -d "$1" ]; then
printf "Error: ‘%s’ is not a directory./n" "$1" >&2
return 1
fi
# Use absolute path for the directory if a relative path was specified.
if command -v readlink >/dev/null ; then
dir="$(readlink -f "$1")"
elif command -v realpath >/dev/null ; then
dir="$(realpath "$1")"
else
case "$1" in
/*)
# The path of the provided directory is already absolute.
dir="$1"
;;
*)
# Prepend the path of the current directory.
dir="$PWD/$1"
;;
esac
printf "Warning: neither ‘readlink’ nor ‘realpath’ are available./n"
printf "Ensure that the specified directory does not contain ‘..’ in its path./n"
fi
# Check that dir is in the user’s PATH.
case ":$PATH:" in
*:"$dir":*)
printf "‘%s’ is in the PATH./n" "$dir"
return 0
;;
*)
printf "‘%s’ is not in the PATH./n" "$dir"
return 1
;;
esac
}
La parte que utiliza :$PATH:
garantiza que el patrón también coincida si la ruta deseada es la primera o la última entrada en la PATH
. Este ingenioso truco se basa en esta respuesta de Glenn Jackman en Unix y Linux .
Este es un enfoque de fuerza bruta, pero funciona en todos los casos, excepto cuando una entrada de ruta contiene dos puntos. Y no se utilizan programas que no sean el shell.
previous_IFS=$IFS
dir_in_path=''no''
export IFS=":"
for p in $PATH
do
[ "$p" = "/path/to/check" ] && dir_in_path=''yes''
done
[ "$dir_in_path" = "no" ] && export PATH="$PATH:/path/to/check"
export IFS=$previous_IFS
He aquí cómo hacerlo sin grep
:
if [[ $PATH == ?(*:)$HOME/bin?(:*) ]]
La clave aquí es hacer que los dos puntos y los comodines sean opcionales usando el constructo ?()
. No debería haber ningún problema con metacaracteres en este formulario, pero si desea incluir citas aquí es donde van:
if [[ "$PATH" == ?(*:)"$HOME/bin"?(:*) ]]
Esta es otra forma de hacerlo utilizando el operador de coincidencia ( =~
) para que la sintaxis sea más parecida a la de grep
:
if [[ "$PATH" =~ (^|:)"${HOME}/bin"(:|$) ]]
No hay absolutamente ninguna necesidad de utilizar utilidades externas como grep
para esto. Esto es lo que he estado usando, que debería ser portable hasta versiones heredadas del shell Bourne.
case :$PATH: # notice colons around the value
in *:$HOME/bin:*) ;; # do nothing, it''s there
*) echo "$HOME/bin not in $PATH" >&2;;
esac
Usar grep
es excesivo, y puede causar problemas si está buscando algo que incluya incluir metacaracteres RE. Este problema se puede resolver perfectamente con el comando incorporado de bash:
if [[ ":$PATH:" == *":$HOME/bin:"* ]]; then
echo "Your path is correctly set"
else
echo "Your path is missing ~/bin, you might want to add it."
fi
Tenga en cuenta que agregar dos puntos antes de la expansión de $ PATH y la ruta de búsqueda resuelve el problema de coincidencia de subcadena; la doble cita de la ruta evita problemas con metacaracteres.
$PATH
es una lista de cadenas separadas por :
que describen una lista de directorios. Un directorio es una lista de cadenas separadas por /
. Dos cadenas diferentes pueden apuntar al mismo directorio (como $HOME
y ~
, o /usr/local/bin
y /usr/local/bin/
). Entonces, debemos arreglar las reglas de lo que queremos comparar / verificar. Sugiero que compare / verifique las cadenas enteras, y no los directorios físicos, sino que elimine los duplicados y los rastreos /
.
Primero elimine el duplicado y el final /
de $PATH
:
echo $PATH | tr -s / | sed ''s///:/:/g;s/://n/g''
Ahora supongamos que $d
contiene el directorio que desea verificar. Luego canalice el comando anterior para verificar $d
en $PATH
.
echo $PATH | tr -s / | sed ''s///:/:/g;s/://n/g'' | grep -q "^$d$" || echo "missing $d"