ユーザー名をスクリプトに渡して、ユーザーのホームディレクトリを見つけます。


8

ユーザーがログインして特定のフォルダーが存在するか、壊れたシンボリックリンクであるかを確認するときに呼び出されるスクリプトを書いています。(これは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。シェルで次のように入力すると、

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  

回答:


16

使用$(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)"

1
正確なスクリプトに固有の+1ソリューション。
ワーナー

2

これは、変数として設定するときに〜georgeを単一引用符で囲むためです。 set -xデバッグに役立ちます。

設定時に引用符を削除するDIRと、変数を設定するとシェルが拡張され、目的のパフォーマンスが得られます。

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、私はその1つでかなりオフでした:-)
カイル・ブラント

set -xは良いヒントです。DIRからの引用の削除は、bash 3.2では機能しませんでした。
クリントンブラックモア

GNU bash、バージョン2.05b.0(1)-release(i486-slackware-linux-gnu)はこちら。
ワーナー、

1

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終了コードが存在する場合、終了コードがゼロになる可能性が高いため、スクリプトが終了後に終了するタイミングを区別することはできません。


+1それらは私の考えの一部でしたが、HOME変数を使用すると、スクリプトへの3番目の引数(これも私を介して)でUSERNAME変数をオーバーライドするため、これはおそらくUSERとして実行されないことを意味すると思います。私はまた、全体を考える傾向||&&(if文の交換)フロー制御が悪いのスタイルであると。
カイル・ブラント

スクリプトはキャスパーを介して実行されます。終了コードを調べるかどうかはわかりませんが、そうである場合は、スクリプトがキャッシュフォルダーを削除するか、キャッシュフォルダーが見つからないため、スクリプトが正常に実行されたことを示すインスタンスと、エラーとして表示されるユーザー名が提供されていません(ログインまたはログアウト時にスクリプトが呼び出されなかったことを示します)。スクリプトが実行された場所のログを見ると、エラーは赤で示されます。
クリントンブラックモア

@Clinton:次に、終了値にゼロ以外の数値を設定します(exit nフォールスルーもエラーの場合はスクリプトの最後に明示的に含めます。ゼロは成功を示し、異なるゼロ以外の数値を使用してさまざまな種類のエラーを示します(独自の目的でそれらの意味を決定するのはあなた次第です)。あるタイプのエラーを別のタイプのエラーと区別する必要がない場合exit 1は、すべての場合に使用するのと同じくらい優れています。一般的なエラー
追って通知があるまで一時停止2010年

unixはunixであり、すべて同じであると思います...そうでない場合を除いて!getentはMacには存在しないようで、通常のユーザーは/ etc / passwdに記載されていません。dsclの兄弟の答えは、OS Xで同じ情報を取得する方法を提案します。私はあなたの答えに感謝し、論理演算子の遅延評価に依存しないようにスクリプトを変更するかもしれません。
クリントンブラックモア

1

パス$HOME/Library/Cachesから判断すると、これはMac OS Xなのでdscl、あなたの友達もそうです。

上記のように、bashそれはあなたのために行われますが、それがMacである場合は、利用可能であることを保証bashできます(したがって、厳密に準拠/bin/shすることで対応できないことを心配する必要はありません)。


それは良い点です。 dscl /Search read /Users/$USERNAME NFSHomeDirectory | cut -f 2 -d " "私が求めていた情報を得るのにちょうどいいようです。
クリントンブラックモア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.