我正在编写一个脚本,当用户登录时会调用该脚本并检查某个文件夹是否存在或是否存在损坏的符号链接。(这是在 Mac OS X 系统上,但问题纯粹是 bash)。
它并不优雅,也无法工作,但现在它看起来像这样:
#!/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."
问题的关键在于波浪号扩展没有按照我希望的方式工作。
假设我有一个名为 的用户george
,他的主文件夹是/a/path/to/georges_home
。如果我在 shell 中输入:
cd ~george
它会带我到相应的目录。如果我输入:
HOME_DIR=~george
echo $HOME_DIR
它给了我:
/a/path/to/georges_home
但是,如果我尝试使用变量,它不起作用:
USERNAME="george"
cd ~$USERNAME
-bash: cd: ~george: No such file or directory
我尝试过使用引号和反引号,但不知道该如何正确扩展。我该如何实现呢?
附录
我只是想发布我完成的脚本(真的,它并不像上面正在进行的工作那么丑陋!)并说它似乎运行正常。
#!/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
答案1
使用$(eval echo ...)
:
michael:~> USERNAME=michael
michael:~> echo ~michael
/home/michael
michael:~> echo ~$USERNAME
~michael
michael:~> echo $(eval echo ~$USERNAME)
/home/michael
所以你的代码应该是这样的:
HOMEDIR="$(eval echo ~$USERNAME)"
答案2
这是因为当设置为变量时,它会将~george 括在单引号中。 set -x
这对于调试很有用。
设置时删除引用DIR
,shell 将在设置变量时扩展,这将为您提供所需的性能。
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
答案3
Bash 内置了用户名和用户主目录的导出变量。~/.bash_profile
例如,如果您在用户从其登录时调用脚本,则无需将值作为参数传递给脚本。
您可以使用$USER
它们,$HOME
因为它们已设置好,并且可在脚本环境中使用,因为它们已标记为已导出。我认为波浪号扩展更多的是为了方便命令行,而不是用于脚本。
DIR="$HOME/Library/Caches"
cd "$DIR" || rm "$DIR" && echo "Removed misdirected Cache folder" && exit 1
通过下列其中一种方式获取用户的主目录可能更可靠:
getent passwd $USER | awk -F: '{print $(NF - 1)}'
或者
awk -F: -v user=$USER 'user == $1 {print $(NF - 1)}' /etc/passwd
此外,exit 0
表示成功。从某种意义上说,您的进程成功删除了目录,但需要删除的事实是一种错误。无论如何,如果您exit 0
此时无法分辨脚本在退出后退出时的区别,echo
因为退出代码很可能为零。
答案4
根据路径判断$HOME/Library/Caches
,这是 Mac OS X,因此dscl
是你的朋友。
如上所述,bash
它为您做到了这一点,但是,如果它是 Mac,您可以保证bash
可以使用(因此您不必担心严格遵守的标准/bin/sh
无法应对它)。