Với tên người dùng được chuyển đến tập lệnh, hãy tìm thư mục chính của người dùng


8

Tôi đang viết một tập lệnh được gọi khi người dùng đăng nhập và kiểm tra xem một thư mục nào đó có tồn tại hay là một liên kết tượng trưng bị hỏng. (Đây là trên hệ thống Mac OS X, nhưng câu hỏi hoàn toàn là bash).

Nó không thanh lịch, và nó không hoạt động, nhưng ngay bây giờ nó trông như thế này:

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

Mấu chốt của vấn đề là việc mở rộng dấu ngã không hoạt động như tôi muốn.

Hãy để chúng tôi nói rằng tôi có một người dùng được đặt tên george, và thư mục nhà của anh ấy là /a/path/to/georges_home. Nếu, tại một vỏ, tôi gõ:

cd ~george

nó đưa tôi đến thư mục thích hợp. Nếu tôi gõ:

HOME_DIR=~george
echo $HOME_DIR

Nó đưa cho tôi:

/a/path/to/georges_home

Tuy nhiên, nếu tôi cố gắng sử dụng một biến, nó không hoạt động:

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

Tôi đã thử sử dụng dấu ngoặc kép và backticks, nhưng không thể tìm ra cách làm cho nó mở rộng đúng cách. Làm thế nào để tôi thực hiện công việc này?


Phụ lục

Tôi chỉ muốn đăng kịch bản hoàn chỉnh của mình (thực sự, nó không xấu như công việc đang tiến triển ở trên!) Và nói rằng nó dường như đang hoạt động đúng.

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

Câu trả lời:


16

Sử dụng $(eval echo ...):

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

Vì vậy, mã của bạn sẽ trông như:

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

1
Giải pháp +1 cụ thể cho tập lệnh chính xác của bạn.
Warner

2

Đó là bởi vì nó sẽ bao quanh ~ george trong các câu đơn khi được đặt làm biến. set -xlà hữu ích để gỡ lỗi.

Xóa trích dẫn khi cài đặt DIRvà trình bao sẽ mở rộng khi đặt biến, điều này sẽ mang lại cho bạn hiệu suất mong muốn.

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, tôi đã rời khỏi đó :-)
Kyle Brandt

set -x là một mẹo hay. Xóa trích dẫn từ DIR không hoạt động đối với tôi theo bash 3.2.
Clinton Blackmore

GNU bash, phiên bản 2.05b.0 (1) -release (i486-slackware-linux-gnu) tại đây.
Warner

1

Bash đã tích hợp các biến xuất cho tên người dùng và thư mục chính của người dùng. Nếu bạn đang gọi tập lệnh của mình khi người dùng đăng nhập từ ~/.bash_profileví dụ của họ , bạn sẽ không cần chuyển các giá trị dưới dạng đối số cho tập lệnh của mình.

Bạn có thể sử dụng $USER$HOMEvì chúng đã được đặt và khả dụng trong môi trường tập lệnh của bạn vì chúng được đánh dấu là đã xuất. Tôi nghĩ việc mở rộng dấu ngã có nghĩa là tiện lợi cho dòng lệnh hơn là một thứ được sử dụng trong các tập lệnh.

DIR="$HOME/Library/Caches"

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

Có thể đáng tin cậy hơn để có được thư mục nhà của người dùng theo một trong các cách sau:

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

hoặc là

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

Ngoài ra, exit 0chỉ ra thành công. Theo một cách nào đó, quá trình của bạn thành công trong việc xóa thư mục, nhưng thực tế là nó cần xóa là một lỗi của một loại. Trong mọi trường hợp, nếu exit 0tại thời điểm này, bạn sẽ không thể biết được sự khác biệt khi tập lệnh thoát ra sau trận chung kết echovì mã thoát rất có thể sẽ bằng không.


+1 Đó là một số khó khăn của tôi, nhưng với các biến HOME tôi nghĩ rằng điều này có thể không được chạy với tư cách là NGƯỜI DÙNG, vì anh ta đã ghi đè biến USERNAME bằng đối số thứ 3 vào tập lệnh (cũng thông qua tôi). Tôi cũng có xu hướng nghĩ rằng toàn bộ ||&&như kiểm soát dòng chảy (thay thế nếu câu lệnh) là phong cách xấu.
Kyle Brandt

Kịch bản sẽ được chạy qua Casper. Tôi không chắc liệu nó có xem mã thoát hay không, nhưng nếu có, tôi muốn bất kỳ trường hợp nào trong đó tập lệnh sẽ xóa thư mục bộ đệm hoặc không tìm thấy để chỉ ra một tập lệnh chạy thành công và bất kỳ trường hợp nào trong đó tên người dùng không được cung cấp (cho biết tập lệnh không được gọi khi đăng nhập hoặc đăng xuất) để hiển thị là một lỗi. Lỗi được gắn cờ màu đỏ khi chúng ta nhìn vào nhật ký nơi tập lệnh chạy.
Clinton Blackmore

@Clinton: Sau đó, bạn sẽ muốn có một số khác không cho giá trị thoát (bao gồm cả phần rõ ràng exit nở cuối tập lệnh nếu rơi qua cũng là một lỗi. Zero biểu thị thành công và bạn có thể sử dụng các số khác không để chỉ ra các loại lỗi khác nhau (tùy thuộc vào bạn để xác định ý nghĩa của chúng cho mục đích riêng của bạn). Nếu bạn không cần phân biệt một loại lỗi với loại khác, thì exit 1tốt nhất là sử dụng trong mọi trường hợp để chỉ ra lỗi chung.
Tạm dừng cho đến khi có thông báo mới.

Tôi đoán unix là unix và hoàn toàn giống nhau ... ngoại trừ khi nó không! Dường như getent không tồn tại trên Mac và người dùng bình thường không được đề cập trong / etc / passwd. Câu trả lời của anh chị em trên dscl gợi ý một cách để có được thông tin tương tự trong OS X. Tôi đánh giá cao câu trả lời của bạn và có thể thay đổi tập lệnh để không dựa vào đánh giá lười biếng của các toán tử logic.
Clinton Blackmore

1

Đánh giá theo đường dẫn $HOME/Library/Caches, đây là Mac OS X, dsclbạn của bạn cũng vậy.

Như đã lưu ý ở trên, bashtuy nhiên, nó dành cho bạn và nếu đó là máy Mac, bạn có thể đảm bảo bashsẽ có sẵn (và vì vậy bạn không cần phải lo lắng về việc tuân thủ nghiêm ngặt /bin/shkhông thể đối phó với nó).


Đó là một điểm hay. dscl /Search read /Users/$USERNAME NFSHomeDirectory | cut -f 2 -d " "dường như là đúng để có được thông tin tôi sau.
Clinton Blackmore
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.