Ich versuche zu prüfen, ob sich ein Verzeichnis bin
in einem Verzeichnis befindet, das sich manchmal ändern kann. In diesem speziellen Fall kann sich die Versionsnummer von Ruby ändern (z. B. $HOME/.gem/ruby/2.6.0/bin
). Folgendes habe ich bisher getan:
#!/usr/bin/env zsh
ruby_gem_home="$HOME/.gem/ruby/*/bin"
if [[ -d $ruby_gem_home ]]; then
echo "The ruby gems directory exists!"
else
echo "Ruby gems directory missing!"
fi
Ich möchte es nicht verwenden, find
da dies Teil eines Anmeldevorgangs ist. Was ist der eleganteste Weg, dies mithilfe integrierter zsh/bash-Befehle zu erreichen?
Danke!
BEARBEITEN:Ich habe vergessen zu erwähnen, dass dies für ein zsh
Skript ist.
Antwort1
Für diesen Fall speziell
Ich glaube nicht, dass es Sinn macht, nach irgendeinem Verzeichnis zu suchen. Was bringt es, ein Verzeichnis zu verwenden, das nicht mit der installierten Version von Ruby übereinstimmt? Und was, wenn der Benutzer ein anderes Verzeichnis konfiguriert hat ~/.gemrc
?
Ich kenne mich mit Ruby nicht so gut aus, aber ich glaube, die richtige Lösung besteht darin, den ersten Eintrag in zu nehmen gempath
.
ruby_gem_home=$(gem environment gempath | sed 's/:.*//')
if [ -z "$ruby_gem_home" ]; then unset ruby_gem_home; fi
In zsh
function set_ruby_gem_home {
emulate -LR zsh
local dirs
dirs=($HOME/.gem/ruby/*/bin(NnOn))
if (($#dirs == 0)); then
unset ruby_gem_home
else
ruby_gem_home=$dirs[0]
fi
}
DerGlob-Qualifizierer N
stellt sicher, dass das Ergebnis ein leeres Array ist und kein Fehler, wenn keine Übereinstimmung vorliegt. Die Glob-Qualifizierer n
sortieren On
die Liste nach absteigenden Versionsnummern. Passen Sie dies an, um ein anderes Element auszuwählen, wenn mehrere Übereinstimmungen vorliegen.
In Bash:
function set_ruby_gem_home {
local dirs
dirs=(~/.gem/ruby/*/bin(NnOn))
if (($#dirs == 0)); then
unset ruby_gem_home
else
ruby_gem_home=$dirs[0]
fi
}
In Bash
function set_ruby_gem_home {
local dirs restore_options
restore_options=$(setopt +o)
shopt -s nullglob
dirs=(~/.gem/ruby/*/bin)
if (($#dirs == 0)); then
unset ruby_gem_home
else
ruby_gem_home=${dirs[${#dirs[@]}-1]}
fi
eval "$restore_options"
}
Hier nehme ich das letzte Array-Element, welches oft aber nicht immer die aktuellste Version ist: 10
wird vor sortiert 9
.
Antwort2
Verwenden Sie ein Array und prüfen Sie, ob das erste Element (also [0] in Bash, [1] in Zsh) des Arrays ein Verzeichnis ist. Beispiel bash
:
# the trailing slash in "$HOME"/.gem/ruby/*/bin/ ensures that
# the glob matches only directories.
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
if [ -d "${rubygemdirs[0]}" ] ; then
echo "At least one ruby gem dir exists"
else
echo "No ruby gem dirs were found"
fi
Um sowohl in zsh
als auch zu arbeiten bash
, müssen Sie zunächst herausfinden, welche Shell derzeit ausgeführt wird. Dadurch erfahren Sie, ob der erste Index eines Arrays 0
oder ist 1
. Außerdem wird dadurch bestimmt, ob Sie mit dem Glob verwenden müssen, (N)
um zsh anzuweisen, NICHT zu beenden, wenn es keine Übereinstimmungen für den Glob gibt (zsh wird standardmäßig beendet, wenn es Glob-Übereinstimmungsfehler gibt).
(an diesem Punkt sollte es langsam offensichtlich werden, dass das Schreiben eines Skripts, das zuverlässig funktioniert,beidebash und zsh wird wahrscheinlich mehr Ärger machen als es wert ist)
if [ -n "$BASH_VERSION" ] ; then
first_idx=0
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
elif [ -n "$ZSH_VERSION" ] ; then
first_idx=1
emulate sh
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
emulate zsh
fi
if [ -d "${rubygemdirs[$first_idx]}" ] ; then
...
Bei Bedarf können Sie auch über das Array iterieren, um zu prüfen, ob ein Element einer bestimmten Version entspricht. zB
for d in "${rubygemdirs[@]}" ; do
[[ $d =~ /2\.6\.0/ ]] && echo found gem dir for ruby 2.6.0
done
Hinweis: Die /
s im regulären Ausdruck sind wörtliche Schrägstriche. Sie markieren nicht den Anfang und das Ende des regulären Ausdrucks wie in sed
.
Antwort3
Platzhalter werden nur in Listenkontexten erweitert, also dort, wo sie zu mehreren Dingen erweitert werden können. Bei einer Zuweisung an eine Skalarvariable können sie nicht erweitert werden, da eine Skalarvariable nur einen Wert enthalten kann.
Mit würden Sie lediglich den String in einer Skalarvariable ruby_gem_home="$HOME/.gem/ruby/*/bin"
speichern und nicht die Liste der Dateien, zu der sich glob im Listenkontext erweitern würde./home/user/.gem/ruby/*/bin
$ruby_gem_home
Listenkontexte in zsh können Argumente für einfache Befehle oder anonyme Funktionen sein, danach for/select x in
, in den Zielen von Umleitungen (wenn multios
aktiviert ist), in Array- oder assoziativen Array-Zuweisungen und einigen anderen Sonderfällen¹.
Sie könnten hier also eine anonyme Funktion verwenden:
() {
unset ruby_gem_home
case $# in
(0) print -u2 "Ruby gems directory missing!";;
(1) print -u2 "The ruby gems directory exists!"
ruby_gem_home=$1;;
(*) print -u2 "More than one ruby gem directory, don't know which to choose!";;
esac
} ~/.gem/ruby/*/bin(N-/)
Hier wird auch der N
Glob-Qualifizierer hinzugefügt, damit der Glob bei fehlender Übereinstimmung zu einer leeren Liste erweitert wird, anstatt einen Fehler zu melden, und -/
um die Datei auf den Typ zu beschränkenVerzeichnis(wird nach der Symlink-Auflösung mit ermittelt -
).
Wenn es mehr als ein Ruby-Gem-Verzeichnis gibt und Sie das mit der höchsten Versionsnummer auswählen möchten, haben Sie folgende Möglichkeiten:
() {
unset ruby_gem_home
case $# in
(0) print -u2 "Ruby gems directory missing!";;
(1) print -u2 "The ruby gems directory exists!"
ruby_gem_home=$1;;
(*) print -ru2 "More than one ruby gem directory, picking $1!"
ruby_gem_home=$1;;
esac
} ~/.gem/ruby/*/bin(N-/nOn)
Wobei n
sich einschaltet numericglobsort
und On
o
in umgekehrter Reihenfolge nach n
demselben sortiert, sodass $1
das mit der höchsten Nummer enthalten ist.
¹ Wie ininfo zsh 'Conditional Expressions'
, es gibt auch einen Sonderfall, wenn die extendedglob
Option aktiviert ist. In diesem Fall können Sie Globs innerhalb verwenden [[ ... ]]
, normalerweise mit den -n
/ -z
-Operatoren. Sie können also verwenden, [[ -n ~/.gem/ruby/*/bin(#qN-/) ]]
um zu prüfen, ob hier mindestens ein solches Verzeichnis vorhanden ist.