web-dev-qa-db-fra.com

Détecter si le chemin de l'utilisateur contient un répertoire spécifique

Avec /bin/bash, comment pourrais-je détecter si un utilisateur a un répertoire spécifique dans sa variable $ PATH?

Par exemple

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
38
epochwolf

Quelque chose de vraiment simple et naïf:

echo "$PATH"|grep -q whatever && echo "found it"

Où que soit ce que vous recherchez. Au lieu de &&, vous pouvez mettre $? dans une variable ou utiliser une instruction if appropriée.

Les limitations incluent:

  • Ce qui précède correspondra aux sous-chaînes de chemins plus importants (essayez de faire correspondre le mot "bin" et il le trouvera probablement, bien que "bin" ne soit pas dans votre chemin,/bin et/usr/bin le sont)
  • Ce qui précède ne développera pas automatiquement les raccourcis comme ~

Ou en utilisant un Perl one-liner:

Perl -e 'exit(!(grep(m{^/usr/bin$},split(":", $ENV{PATH}))) > 0)' && echo "found it"

Cela a toujours la limitation qu'il ne fera aucune expansion du shell, mais n'échouera pas si une sous-chaîne correspond. (Ce qui précède correspond à "/usr/bin", au cas où ce n'était pas clair).

5
Adam Batkin

Utiliser grep est excessif et peut causer des problèmes si vous recherchez quelque chose qui inclut des métacaractères RE. Ce problème peut être résolu parfaitement avec la commande [[ intégrée 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

Notez que l'ajout de deux points avant le développement de $ PATH et le chemin à rechercher résolvent le problème de correspondance de sous-chaîne; la double cotation du chemin évite les problèmes de méta-caractères.

116
Gordon Davisson

Voici comment le faire sans grep:

if [[ $PATH == ?(*:)$HOME/bin?(:*) ]]

La clé ici est de rendre les deux-points et les caractères génériques facultatifs à l'aide de la construction ?(). Il ne devrait y avoir aucun problème avec les métacaractères dans ce formulaire, mais si vous voulez inclure des guillemets, c'est ici qu'ils vont:

if [[ "$PATH" == ?(*:)"$HOME/bin"?(:*) ]]

C'est une autre façon de le faire en utilisant l'opérateur de correspondance (=~), de sorte que la syntaxe ressemble davantage à celle de grep:

if [[ "$PATH" =~ (^|:)"${HOME}/bin"(:|$) ]]
10
Dennis Williamson

Il n’est absolument pas nécessaire d’utiliser des utilitaires externes tels que grep pour cela. Voici ce que j'ai utilisé, qui devrait être portable, même pour les versions héritées du Bourne Shell.

case :$PATH: # notice colons around the value
  in *:$HOME/bin:*) ;; # do nothing, it's there
     *) echo "$HOME/bin not in $PATH" >&2;;
esac
3
tripleee

J'ai écrit la fonction Shell suivante pour signaler si un répertoire est répertorié dans la PATH actuelle. Cette fonction est compatible POSIX et s'exécutera dans des interpréteurs compatibles, tels que Dash et Bash (sans utiliser les fonctionnalités spécifiques à Bash).

Il inclut des fonctionnalités pour convertir un chemin relatif en un chemin absolu. Il utilise les utilitaires readlink ou realpath pour cela, mais ces outils ne sont pas nécessaires si le répertoire fourni n'a pas .. ou d'autres liens en tant que composants de son chemin. En dehors de cela, la fonction ne nécessite aucun programme externe au 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 partie utilisant :$PATH: garantit que le modèle correspond également si le chemin souhaité est la première ou la dernière entrée de la PATH. Cette astuce est basée sur cette réponse de Glenn Jackman sous Unix & Linux .

1

$PATH est une liste de chaînes séparées par : décrivant une liste de répertoires. Un répertoire est une liste de chaînes séparées par /. Deux chaînes différentes peuvent pointer vers le même répertoire (comme $HOME et ~, ou /usr/local/bin et /usr/local/bin/). Nous devons donc fixer les règles de ce que nous voulons comparer/vérifier. Je suggère de comparer/vérifier les chaînes entières, et non les répertoires physiques, mais supprimer les / dupliqués et finaux.

Commencez par supprimer les / en double et fin de $PATH:

 echo $ PATH | tr -s/| sed 's/\ /: /:/g; s /:/\ n/g' 

Supposons maintenant que $d contienne le répertoire que vous voulez vérifier. Ensuite, dirigez la commande précédente pour vérifier $d dans $PATH.

 echo $ PATH | tr -s/| sed 's/\ /: /:/g; s /:/\ n/g' | grep -q "^ $ d $" || echo "missing $ d" 
0
jcr38

C'est une approche de force brute, mais cela fonctionne dans tous les cas, sauf lorsqu'une entrée de chemin contient deux points. Et aucun programme autre que Shell n’est utilisé.

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
0
bmacnaughton