Dengan nama pengguna yang diteruskan ke skrip, temukan direktori home pengguna

8

Saya menulis skrip yang dipanggil saat pengguna masuk dan memeriksa apakah folder tertentu ada atau ada symlink yang rusak. (Ini pada sistem Mac OS X, tetapi pertanyaannya murni bash).

Itu tidak elegan, dan tidak berfungsi, tetapi sekarang ini terlihat seperti ini:

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

Inti masalahnya adalah bahwa ekspansi tilde tidak berfungsi seperti yang saya inginkan.

Katakanlah saya memiliki nama pengguna george, dan folder rumahnya adalah /a/path/to/georges_home. Jika, pada suatu shell, saya mengetik:

cd ~george

itu membawa saya ke direktori yang sesuai. Jika saya mengetik:

HOME_DIR=~george
echo $HOME_DIR

Ini memberi saya:

/a/path/to/georges_home

Namun, jika saya mencoba menggunakan variabel, itu tidak berfungsi:

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

Saya sudah mencoba menggunakan tanda kutip dan backticks, tetapi tidak tahu bagaimana membuatnya berkembang dengan baik. Bagaimana saya membuat ini bekerja?


Tambahan

Saya hanya ingin memposting skrip saya yang sudah selesai (sungguh, itu tidak seburuk pekerjaan yang sedang berjalan di atas!) Dan mengatakan bahwa itu tampaknya berfungsi dengan benar.

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

Jawaban:

16

Gunakan $(eval echo ...):

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

Jadi kode Anda akan terlihat seperti:

HOMEDIR="$(eval echo ~$USERNAME)"
MikeyB
sumber
1
Solusi +1 khusus untuk skrip persis Anda.
Warner
2

Itu karena ia akan menyertakan ~ george dalam tanda kutip tunggal ketika ditetapkan sebagai variabel. set -xberguna untuk debugging.

Hapus pengaturan kutip ketika DIRdan shell akan berkembang ketika mengatur variabel, yang akan memberi Anda kinerja yang Anda inginkan.

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
sumber
1
+1, saya jauh dari yang itu :-)
Kyle Brandt
set -x adalah tip yang bagus. Menghapus kutipan dari DIR tidak berfungsi untuk saya di bawah bash 3.2.
Clinton Blackmore
GNU bash, versi 2.05b.0 (1) -release (i486-slackware-linux-gnu) di sini.
Warner
1

Bash memiliki variabel yang diekspor bawaan untuk nama pengguna dan direktori home pengguna. Jika Anda memanggil skrip Anda saat pengguna masuk dari skrip mereka~/.bash_profile misalnya, Anda tidak perlu meneruskan nilai sebagai argumen ke skrip Anda.

Anda dapat menggunakan $USERdan $HOMEkarena sudah disetel dan tersedia di lingkungan skrip Anda karena ditandai sebagai diekspor. Saya pikir ekspansi tilde dimaksudkan untuk lebih kenyamanan baris perintah daripada sesuatu yang digunakan dalam skrip.

DIR="$HOME/Library/Caches"

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

Mungkin lebih dapat diandalkan untuk mendapatkan direktori home pengguna dengan salah satu cara berikut:

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

atau

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

Juga, exit 0menunjukkan kesuksesan. Di satu sisi, proses Anda berhasil menghapus direktori, tetapi fakta bahwa itu perlu dihapus adalah semacam kesalahan. Bagaimanapun, jika Anda exit 0pada titik ini Anda tidak akan dapat membedakannya ketika skrip keluar setelah final echokarena kode keluar kemungkinan besar akan nol.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
+1 Itu adalah beberapa kesulitan saya, tetapi dengan variabel HOME saya pikir ini mungkin dimaksudkan untuk tidak dijalankan sebagai USER, karena ia menimpa variabel USERNAME dengan argumen ke-3 pada skrip (yang juga membuat saya tidak suka). Saya juga cenderung menganggap keseluruhan ||dan &&sebagai kontrol aliran (mengganti pernyataan jika) adalah gaya yang buruk.
Kyle Brandt
Script akan dijalankan melalui Casper. Saya tidak yakin apakah itu terlihat pada kode keluar, tetapi jika itu benar, saya ingin ada contoh di mana skrip menghapus folder cache atau tidak menemukan satu untuk menunjukkan keberhasilan menjalankan skrip, dan setiap contoh di mana nama pengguna tidak diberikan (menunjukkan skrip tidak dipanggil saat masuk atau keluar) untuk ditampilkan sebagai kesalahan. Kesalahan ditandai dengan warna merah ketika kita melihat log tempat skrip dijalankan.
Clinton Blackmore
@Clinton: Maka Anda akan ingin memiliki angka bukan nol untuk nilai keluar (termasuk eksplisit exit ndi akhir skrip jika gagal juga merupakan kesalahan. Nol menunjukkan keberhasilan dan Anda dapat menggunakan nomor bukan nol yang berbeda untuk menunjukkan berbagai jenis kesalahan (terserah Anda untuk menentukan maknanya untuk tujuan Anda sendiri). Jika Anda tidak perlu membedakan satu jenis kesalahan dari yang lain, maka exit 1sama baiknya dengan yang digunakan dalam semua kasus untuk menunjukkan suatu kesalahan umum
Dijeda hingga pemberitahuan lebih lanjut
Saya kira unix adalah unix dan semuanya sama ... kecuali kalau tidak! Tampaknya getent tidak ada di Mac, dan pengguna normal tidak disebutkan di / etc / passwd. Jawaban saudara pada dscl menyarankan cara untuk mendapatkan info yang sama di bawah OS X. Saya menghargai jawaban Anda, dan mungkin mengubah skrip untuk tidak bergantung pada evaluasi malas operator logis.
Clinton Blackmore
1

Menilai dari jalurnya $HOME/Library/Caches, ini adalah Mac OS X, begitu dscljuga teman Anda.

Seperti disebutkan di atas, bashapakah itu untuk Anda, dan jika itu adalah Mac, Anda dapat menjamin bashakan tersedia (dan karenanya Anda tidak perlu khawatir tentang orang yang benar-benar /bin/shtidak bisa mengatasinya).

Mo.
sumber
Itu poin yang bagus. dscl /Search read /Users/$USERNAME NFSHomeDirectory | cut -f 2 -d " "tampaknya tepat untuk mendapatkan informasi yang saya cari.
Clinton Blackmore