readlinkのメモ

readlinkコマンドはシンボリックリンクを辿り、リンク先を表示する。しかしこのままではファイルへのパスとして妥当なものにならない。

こういうときはdirnameと組み合わせればよい。

  # 実際のファイル名を出力する
  D=$(dirname $i)
  L=$(readlink $i)
  if [ -z "$L" ] ; then
    echo $i
  elif [ -z "$D" -o "$D" = "." -o $(echo $L | cut -c 1) = "/" ] ; then
    echo $L
  else
    echo $D/$L
  fi

しかし、これでは「../」などが残ってしまう。そこで、こういう感じのを噛ませる。sedでパターンマッチだけでやろうとしたがなかなかいまいちになったのでPerlを登場させてしまった(不覚)。

  echo $1 | \
  perl -ne '
  @a=split("/");
  for($i=0; $i<=$#a; $i++){
    if($a[$i] eq ".." & $#b!=-1 & $b[$#b] ne ".."){
      pop(@b);
    }elsif($a[$i] ne "."){
      push(@b, $a[$i]);
    } 
  }
  print join("/", @b)."\n";'

だいたい実際のファイル名が得られる。厳密ではないと思うけど。

組み合わせると、以下のようになる。しばらくこれで使ってみようと思う。なんかでもバグってるかも。

<br /> #! /bin/sh</p> <p>delete_parent(){<br /> echo $1 | \<br /> perl -ne '<br /> @a=split("/");<br /> for($i=0; $i<=$#a; $i++){ if($a[$i] eq ".." &amp; $#b!=-1 &amp; $b[$#b] ne ".."){ pop(@b); }elsif($a[$i] ne "."){ push(@b, $a[$i]); } } print join("/", @b)."\n";' } delete_parent_old(){ O=$1 while [ "$S" != "$O" ]; do S=$O O=$(echo -n $S | perl -pe 's|/([^\./][^/]+)/../|/|g;s|/./|/|g;s|^[^\./][^/]+/../||g;') done echo $O } for i; do D=$(dirname $i) L=$(readlink $i) if [ -z "$L" ] ; then echo $(delete_parent $i) elif [ -z "$D" -o "$D" = "." -o $(echo $L | cut -c 1) = "/" ] ; then echo $(delete_parent $L) else echo $(delete_parent $D/$L) fi done

/bin/shとは書いたものの、素のBourne Shellでは無理だろうな。bashなら動くようだ。

勿論これだけの操作では1つしかリンクを辿らない。また途中のディレクトリにシンボリックリンクがあってもそれは辿らない。指定されたファイル名のみについて1つ辿ってそれらしいファイル名を返す、というものだ。

絶対パスにしたければ、先頭文字が/でない場合に先頭に$PWDをつければよい。いじょう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です