Con un nome utente passato a uno script, trova la home directory dell'utente


8

Sto scrivendo uno script che viene chiamato quando un utente accede e controlla se esiste una determinata cartella o se è un link simbolico non funzionante. (Questo è su un sistema Mac OS X, ma la domanda è puramente bash).

Non è elegante e non funziona, ma in questo momento sembra così:

#!/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."

Il nocciolo del problema è che l'espansione della tilde non funziona come vorrei.

Diciamo che ho un utente di nome georgee che la sua cartella principale è /a/path/to/georges_home. Se, in una shell, scrivo:

cd ~george

mi porta nella directory appropriata. Se scrivo:

HOME_DIR=~george
echo $HOME_DIR

Mi dà:

/a/path/to/georges_home

Tuttavia, se provo a utilizzare una variabile, non funziona:

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

Ho provato a usare virgolette e backtick, ma non riesco a capire come farlo espandere correttamente. Come faccio a farlo funzionare?


appendice

Volevo solo pubblicare il mio script completato (davvero, non è brutto come il lavoro in corso sopra!) E dire che sembra funzionare correttamente.

#!/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  

Risposte:


16

Utilizzare $(eval echo ...):

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

Quindi il tuo codice dovrebbe apparire come:

HOMEDIR="$(eval echo ~$USERNAME)"

1
+1 soluzione specifica per lo script esatto.
Warner,

2

È perché racchiuderà ~ george tra virgolette singole quando impostato come variabile. set -xè utile per il debug.

Rimuovi le quotazioni durante l'impostazione DIRe la shell si espanderà durante l'impostazione della variabile, che ti darà le prestazioni desiderate.

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

1
+1, ero molto lontano da quello :-)
Kyle Brandt,

set -x è un bel consiglio. La rimozione del preventivo da DIR non ha funzionato per me in bash 3.2.
Clinton Blackmore,

GNU bash, versione 2.05b.0 (1) -release (i486-slackware-linux-gnu) qui.
Warner,

1

Bash ha le variabili esportate integrate per nome utente e home directory dell'utente. Se stai chiamando il tuo script quando l'utente accede dal loro ~/.bash_profilead esempio, non dovrai passare i valori come argomenti al tuo script.

È possibile utilizzare $USERe $HOMEpoiché sono già impostati e disponibili nell'ambiente dello script poiché sono contrassegnati come esportati. Penso che l'espansione della tilde sia pensata per essere più una comodità della riga di comando che qualcosa che viene usato negli script.

DIR="$HOME/Library/Caches"

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

Potrebbe essere più affidabile ottenere la home directory dell'utente in uno dei seguenti modi:

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

o

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

Inoltre, exit 0indica il successo. In un certo senso, il processo riesce a eliminare la directory, ma il fatto che debba essere eliminato è un errore di un tipo. In ogni caso, se exit 0a questo punto non sarai in grado di dire la differenza quando lo script esce dopo la finale echopoiché il codice di uscita molto probabilmente sarà zero.


+1 Questi erano alcuni dei miei punti di forza, ma con le variabili HOME penso che questo forse non dovrebbe essere eseguito come USER, poiché sostituisce la variabile USERNAME con il 3 ° argomento dello script (che anche attraverso di me). Tendo anche a pensare il tutto ||e &&come controllo di flusso (in sostituzione di istruzioni if) è stile cattivo.
Kyle Brandt,

Lo script verrà eseguito tramite Casper. Non sono sicuro se esamina i codici di uscita, ma in tal caso, desidero qualsiasi istanza in cui lo script elimina la cartella della cache o non ne trova una che indichi una corretta esecuzione dello script e qualsiasi istanza in cui il il nome utente non è stato fornito (indicando che lo script non è stato chiamato all'accesso o alla disconnessione) per essere visualizzato come errore. Gli errori sono contrassegnati in rosso quando esaminiamo i registri di dove è stato eseguito lo script.
Clinton Blackmore,

@Clinton: Quindi vorrai avere un numero diverso da zero per il valore di uscita (incluso un esplicito exit nalla fine dello script se la caduta è anche un errore. Zero indica il successo e puoi usare diversi numeri diversi da zero per indica diversi tipi di errori (spetta a te determinarne il significato per i tuoi scopi). Se non hai bisogno di distinguere un tipo di errore da un altro, allora exit 1è buono come uno da usare in tutti i casi per indicare un errore generale
Sospeso fino a nuovo avviso

Immagino che unix sia unix ed è lo stesso ... tranne quando non lo è! Sembra che getent non esista sul Mac e che gli utenti normali non siano menzionati in / etc / passwd. La risposta tra fratelli su dscl suggerisce un modo per ottenere le stesse informazioni su OS X. Apprezzo la tua risposta e potrei cambiare lo script per non fare affidamento su una valutazione pigra degli operatori logici.
Clinton Blackmore,

1

A giudicare dal percorso $HOME/Library/Caches, questo è Mac OS X, così dsclcome il tuo amico.

Come notato sopra, lo bashfa per te, tuttavia, e se si tratta di un Mac, puoi garantire bashche sarà disponibile (e quindi non devi preoccuparti di una conformità rigorosa che /bin/shnon è in grado di far fronte).


È un buon punto. dscl /Search read /Users/$USERNAME NFSHomeDirectory | cut -f 2 -d " "sembra essere giusto per ottenere le informazioni che stavo cercando.
Clinton Blackmore,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.