シェルスクリプトでファイルがシンボリックリンクか判定する方法

再び追記_2012/10/31_15時頃

もう少しコマンドの数を減らせることに気づいたので追記します

調べたいファイル名=~/.vim

if [ -n "`find \"${調べたいファイル名}\" -maxdepth 0 -type l`" ];then
    echo "シンボリックリンクです"
else
    echo "シンボリックリンク以外の何か(存在しない場合も含む)"
fi

ちなみに速度は比較していないのでどれが早いのか不明
シンボリックリンクであれば標準出力されるのでそれを利用して-nオプションでされたかどうかを判定してます
ちなみにfindのtypeのlを変えることによってディレクトリやソケットや名前付きパイプにも応用できたりします
ちなみにちゃんと``を""で囲ってやらないと正常に動かないので注意…一度囲まないで公開してしまった
そしてmaxdepthも指定しないとディレクトリを指定した場合に期待していない結果になるけどosによってはこのオプションはないらしいから試してないけどhead -1にパイプしてもいいかもしれない

改良後(追記後)

何度もlsを実行しなくてもいいことに気づいたので追記します*1

調べたいファイル名=~/.vim

ls -l1ad ${調べたいファイル名} 2>/dev/null|grep "^l" > /dev/null 2>&1
if [ ${?} == "0" ];then
    echo "シンボリックリンクです"
else
    echo "シンボリックリンク以外の何か(存在しない場合も含む)"
fi

最初にlというシンボリックリンクを示す文字があるかで判定しています
存在しないファイルを見に行った時もlから始まる文字が出力されるのですが
それはエラーなので2>/dev/nullで捨てて無視できるようにしてます

以下は改良前の記事(追記前)

bashスクリプトでは

if [[ -L ~/.vim ]]
then
#シンボリックリンクだったら
else
#そうじゃなかったら
fi

のように書けるみたいですが
もしかしたらshスクリプトではできない?みたいですし
書いてみました

追記:ファイル名の最後が@でもちゃんと動くように修正しました
調べたいファイル名=~/.vim

ls -F1ad ${調べたいファイル名} 2>/dev/null|grep "@$" > /dev/null 2>&1
if [ ${?} == "0" -a "$(ls -F1ad ${調べたいファイル名} 2>/dev/null)" != "$(ls -1ad ${調べたいファイル名} 2>/dev/null)" ];then
    echo "シンボリックリンクです"
else
    echo "シンボリックリンク以外の何か(存在しない場合も含む)"
fi

こんな感じです
しかし変数名に日本語を使うとエラーを吐くのでやめましょう

これだけだと寂しいので解説すると

ls -F1ad ${調べたいファイル名}

これでまず
Fでファイルのタイプを名前の後ろに付け足します。シンボリックリンクだったら語尾に@がつきます
1で1行ずつ表示(ファイルの対象は1つしかないのでいらないと思いますが何となく)
aでドットから始まるファイルも対象に
dでディレクトリを指定した場合は中身を表示するのではなくそれそのものが対象に

これを~/.vimシンボリックリンクだとして実際にやってみると

% ls -F1ad ~/.vim
/home/noter/.vim@

こんな感じになります

後ろの

2>/dev/null

これはもし存在しないファイルが対象だった時などにエラーが出たら邪魔なので個人的に消します

ちなみに恥ずかしい話ですが

ls -F1ad ~/.vim > /dev/null 2>&1|grep "@$" > /dev/null 2>&1

こう書いて~/.vimシンボリックリンクなのに
シンボリックリンクが存在しないと言われて数分悩みました
当たり前なんですがパイプで渡す予定の標準出力も捨てちゃってます
みなさんも気をつけましょう

それでは話を戻して

grep "@$" > /dev/null 2>&1

この部分はgrepで語尾が@の行だけを抜き出して出力はいらないので捨てちゃってます
$は一番後ろという意味です

if [ ${?} == "0" -a "$(ls -F1ad ${調べたいファイル名})" != "$(ls -1ad ${調べたいファイル名})" ];then
    echo "シンボリックリンクです"
else
    echo "シンボリックリンク以外の何か(存在しない場合も含む)"
fi

最後のここでシンボリックリンクか判定してます
条件を順番に見て行きましょう

if [ ${?} == "0" ]

grepの戻り値を判定してます
この場合だと0が見つかった。1が見つからなかった。が返るようです
詳しくはman grepのEXIT STATUSに書いてあります

if [ "$(ls -F1ad ${調べたいファイル名} 2>/dev/null)" != "$(ls -1ad ${調べたいファイル名} 2>/dev/null)" ]

ここでファイル名に最後に@が使われていた場合にきちんと動かない場合があるので
その@はls -Fでつけられたものかファイル名のものかを判定してます
これも2>/dev/nullがあるのは個人的にエラー表示は邪魔なので消してます

ちなみに間にあった-aはandという意味です
つまりさっきの2つの条件が両方とも合えば真になります

*1:一回別記事に書いたのですが、この記事に追記した方がいいかなと思って別の記事は消してここに書きました