Suchen Sie mit einem an ein Skript übergebenen Benutzernamen das Home-Verzeichnis des Benutzers

8

Ich schreibe ein Skript, das aufgerufen wird, wenn sich ein Benutzer anmeldet und prüft, ob ein bestimmter Ordner vorhanden ist oder ob ein Symlink defekt ist. (Dies ist auf einem Mac OS X-System, aber die Frage ist rein bash).

Es ist nicht elegant und funktioniert nicht, aber im Moment sieht es so aus:

#!/bin/bash

# Often users have a messed up cache folder -- one that was redirected
# but now is just a broken symlink.  This script checks to see if
# the cache folder is all right, and if not, deletes it
# so that the system can recreate it.

USERNAME=$3
if [ "$USERNAME" == "" ] ; then
    echo "This script must be run at login!" >&2
    exit 1
fi

DIR="~$USERNAME/Library/Caches"

cd $DIR || rm $DIR && echo "Removed misdirected Cache folder" && exit 0

echo "Cache folder was fine."

Der Kern des Problems ist, dass die Tilde-Erweiterung nicht so funktioniert, wie ich es gerne hätte.

Nehmen wir an, ich habe einen Benutzer namens georgeund sein Home-Ordner ist /a/path/to/georges_home. Wenn ich in einer Shell Folgendes eingebe:

cd ~george

es bringt mich in das entsprechende Verzeichnis. Wenn ich tippe:

HOME_DIR=~george
echo $HOME_DIR

Es gibt mir:

/a/path/to/georges_home

Wenn ich jedoch versuche, eine Variable zu verwenden, funktioniert dies nicht:

USERNAME="george"
cd ~$USERNAME
-bash: cd: ~george: No such file or directory

Ich habe versucht, Anführungszeichen und Backticks zu verwenden, kann aber nicht herausfinden, wie ich es richtig erweitern kann. Wie mache ich das?


Nachtrag

Ich wollte nur mein fertiges Skript veröffentlichen (wirklich, es ist nicht so hässlich wie die oben genannten Arbeiten!) Und sagen, dass es richtig zu funktionieren scheint.

#!/bin/bash

# Often users have a messed up cache folder -- one that was redirected
# but now is just a broken symlink.  This script checks to see if
# the cache folder is all right, and if not, deletes it
# so that the system can recreate it.

#set -x # turn on to help debug

USERNAME=$3 # Casper passes the user name as parameter 3
if [ "$USERNAME" == "" ] ; then
    echo "This script must be run at login!" >&2
    exit 1  # bail out, indicating failure
fi

CACHEDIR=`echo $(eval echo ~$USERNAME/Library/Caches)`

# Show what we've got
ls -ldF "$CACHEDIR"

if [ -d "$CACHEDIR" ] ; then
    # The cache folder either exists or is a working symlink
    # It doesn't really matter, but might as well output a message stating which
    if [ -L "$CACHEDIR" ] ; then
        echo "Working symlink found at $CACHEDIR was not removed."
    else
        echo "Normal directory found at $CACHEDIR was left untouched."
    fi
else
    # We almost certainly have a broken symlink instead of the directory
    if [ -L "$CACHEDIR" ] ; then
        echo "Removing broken symlink at $CACHEDIR."
        rm "$CACHEDIR"
    else
        echo "Abnormality found at $CACHEDIR.  Trying to remove." >&2
        rm -rf "$CACHEDIR"
        exit 2  # mark this as a bad attempt to fix things; it isn't clear if the fix worked
    fi
fi

# exit, indicating that the script ran successfully,
# and that the Cache folder is (almost certainly) now in a good state
exit 0  
Clinton Blackmore
quelle

Antworten:

16

Verwendung $(eval echo ...):

michael:~> USERNAME=michael
michael:~> echo ~michael
/home/michael
michael:~> echo ~$USERNAME
~michael
michael:~> echo $(eval echo ~$USERNAME)
/home/michael

Ihr Code sollte also folgendermaßen aussehen:

HOMEDIR="$(eval echo ~$USERNAME)"
MikeyB
quelle
1
+1 Lösung speziell für Ihr genaues Skript.
Warner
2

Dies liegt daran, dass die ~ George in einfache Anführungszeichen eingeschlossen wird, wenn sie als Variable festgelegt wird. set -xist nützlich zum Debuggen.

Entfernen Sie das Anführungszeichen beim Einstellen, DIRund die Shell wird beim Einstellen der Variablen erweitert, wodurch Sie die gewünschte Leistung erzielen.

lrwxrwxrwx  1 root root 4 Sep 10  2004 /bin/sh -> bash*
wmoore@bitbucket(/tmp)$ cat test.sh
#!/bin/bash
set -x

cd ~root

DIR=~root

cd $DIR

DIR="~root"

cd $DIR
wmoore@bitbucket(/tmp)$ sh test.sh
+ cd /root
test.sh: line 4: cd: /root: Permission denied
+ DIR=/root
+ cd /root
test.sh: line 8: cd: /root: Permission denied
+ DIR=~root
+ cd '~root'
test.sh: line 12: cd: ~root: No such file or directory
Warner
quelle
1
+1, ich war weit weg von diesem :-)
Kyle Brandt
set -x ist ein schöner Tipp. Das Entfernen des Zitats aus DIR hat unter Bash 3.2 bei mir nicht funktioniert.
Clinton Blackmore
GNU Bash, Version 2.05b.0 (1) -Veröffentlichung (i486-Slackware-Linux-Gnu) hier.
Warner
1

Bash hat exportierte Variablen für den Benutzernamen und das Home-Verzeichnis des Benutzers integriert. Wenn Sie Ihr Skript aufrufen, wenn sich der Benutzer beispielsweise von dort aus anmeldet ~/.bash_profile, müssen Sie die Werte nicht als Argumente an Ihr Skript übergeben.

Sie können verwenden $USERund $HOMEda sie bereits festgelegt und in der Umgebung Ihres Skripts verfügbar sind, da sie als exportiert markiert sind. Ich denke, Tilde-Erweiterung soll eher eine Befehlszeilen-Annehmlichkeit sein als etwas, das in Skripten verwendet wird.

DIR="$HOME/Library/Caches"

cd "$DIR" || rm "$DIR" && echo "Removed misdirected Cache folder" && exit 1

Es ist möglicherweise zuverlässiger, das Home-Verzeichnis des Benutzers auf eine der folgenden Arten abzurufen:

getent passwd $USER | awk -F: '{print $(NF - 1)}'

oder

awk -F: -v user=$USER 'user == $1 {print $(NF - 1)}' /etc/passwd

Auch exit 0zeigt Erfolg. In gewisser Weise ist Ihr Prozess beim Löschen des Verzeichnisses erfolgreich, aber die Tatsache, dass es gelöscht werden muss, ist eine Art Fehler. In jedem Fall können Sie exit 0zu diesem Zeitpunkt keinen Unterschied feststellen, wenn das Skript nach dem Finale beendet wird, echoda der Exit-Code höchstwahrscheinlich Null ist.

Bis auf weiteres angehalten.
quelle
+1 Das waren einige meiner Probleme, aber mit den HOME-Variablen denke ich, dass dies möglicherweise nicht als USER ausgeführt werden soll, da er die USERNAME-Variable mit dem 3. Argument für das Skript überschreibt (was auch durch mich deaktiviert ist). Ich neige auch dazu, das Ganze ||und &&als Flusskontrolle (Ersetzen von if-Anweisungen) für einen schlechten Stil zu halten.
Kyle Brandt
Das Skript wird über Casper ausgeführt. Ich bin nicht sicher, ob es sich um die Exit-Codes handelt, aber wenn ja, möchte ich eine Instanz, in der das Skript entweder den Cache-Ordner löscht oder keine findet, die auf eine erfolgreiche Ausführung des Skripts hinweist, und eine Instanz, in der die Der Benutzername wurde nicht angegeben (was darauf hinweist, dass das Skript beim Anmelden oder Abmelden nicht aufgerufen wurde), um als Fehler angezeigt zu werden. Fehler werden rot markiert, wenn wir uns die Protokolle ansehen, in denen das Skript ausgeführt wurde.
Clinton Blackmore
@Clinton: Dann möchten Sie eine Zahl ungleich Null für den Exit-Wert haben (einschließlich einer expliziten Zahl exit nam Ende des Skripts, wenn das Durchfallen ebenfalls ein Fehler ist. Null zeigt Erfolg an und Sie können verschiedene Zahlen ungleich Null verwenden Geben Sie verschiedene Fehlertypen an (es liegt an Ihnen, deren Bedeutung für Ihre eigenen Zwecke zu bestimmen). Wenn Sie einen Fehlertyp nicht von einem anderen unterscheiden müssen, können Sie exit 1in allen Fällen so gut wie jeden anderen Fehler angeben allgemeiner Fehler.
Bis auf weiteres angehalten.
Ich denke, Unix ist Unix und ist alle gleich ... außer wenn es nicht ist! Es scheint, dass getent auf dem Mac nicht existiert und normale Benutzer in / etc / passwd nicht erwähnt werden. Die Geschwisterantwort auf dscl schlägt eine Möglichkeit vor, die gleichen Informationen unter OS X zu erhalten. Ich schätze Ihre Antwort und könnte das Skript so ändern, dass es sich nicht auf eine verzögerte Auswertung logischer Operatoren verlässt.
Clinton Blackmore
1

Dem Pfad nach zu urteilen $HOME/Library/Caches, ist dies Mac OS X, genau dsclwie Ihr Freund.

Wie oben erwähnt, basherledigt es dies jedoch für Sie, und wenn es sich um einen Mac handelt, können Sie garantieren bash, dass dieser verfügbar ist (und Sie müssen sich keine Sorgen machen, dass eine strikte Konformität /bin/shnicht in der Lage ist, damit umzugehen).

Mo.
quelle
Das ist ein guter Punkt. dscl /Search read /Users/$USERNAME NFSHomeDirectory | cut -f 2 -d " "scheint ungefähr richtig zu sein, um die Informationen zu bekommen, nach denen ich gesucht habe.
Clinton Blackmore