その繋がりは,嘘です.幻想です. 〜 `ls` と相対パス

ひさしぶり.だ.

この度は,lnコマンドに関するメモです.
リンクを作成するアレですね.

今更lnかよ,と言われていそうですが,えぇ,この話は,まさにその"今更"でした.

こんなエラーに出逢いました.

ln: <File Name>: File exists

以降の話の為にman lnの内容を引用しておこうかと思います.;

SYNOPSIS
     ln [-Ffhinsv] source_file [target_file]
:
DESCRIPTION
The ln utility creates a new directory entry (linked file) which has the same modes as the original file.
:

ln自身のこれ以上の詳細については,割愛.*1

という事で,この度恥を晒そう記録と記憶に留めておこうと思ったことは...

相対パスlnを扱う場合,第1引数(source_file)のパスは,第2引数(target_file)側をカレントとして定義しなくてはならない

もしかして,"カレント"って言う表現はちょっと適切じゃないかな...?

lnコマンドで指定する第一引数..は、symlinkを貼るディレクトリから見たパスを指定するので、..

今回の内容はこれに限る.

もうね,無知ってね,アレですね.あーやだ.

% sw_ver
sw_vers is correct? [n,y,a,e]: y
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H15

いい加減,OS,アップグレードしなくちゃなぁ.




自分のイメージを自分の言葉で言語化しますと.
lnを,相対パスで利用した場合,
パスは,
source_fileのリンクをtarget_fileに...」と言うよりは,
「symlinktarget_fileは,source_fileから...」なイメージで捉えた方が良い.のかも.

sylink側から,source_fileを捉える感覚と言うか...

は?笑

こんな仕様があることを知った時,今まで知らずにlnを使っていた自分にちょっとゾッとした.

その後改めて,"ln 相対パス"等でググったら,まぁ出てくる出てくる.
しかも随分と過去の議論のようで...

あぁダメだ.

自嘲的な気分でいっぱい.

切っ掛け

ここで大変恐縮なのですが,さらにもうちょっと背景やら経緯をメモさせていただきたいと思います.
申し訳ございません.*2

震源地 ~ ln "File exists" のスクリプト

作業を始めるにあたって,軽く振る舞いを見てみたいな,と思って用意した小さいスクリプト

それはそれは実に稚拙な内容のスクリプトで,
結構に恥ずかしいレベルの内容なのですが,
これからの話のために,ありのまま晒しておこうかと思います.

ちなみに,これは間違ったスクリプトです.
説明のために. ;

#!/bin/bash -eu

SOURCE=""
DESTINATION="bkup"

LATEST="Latest"

readonly DATE_FORMAT=$(date "+%H-%M-%S")

if [[ ! -e "$DESTINATION/$DATE_FORMAT" ]] ; then
  mkdir -p "$DESTINATION/$DATE_FORMAT"
fi

if [[ -e "$DESTINATION/$LATEST" ]] ; then
  rm "$DESTINATION/$LATEST"
fi

ln -s "$DESTINATION/$DATE_FORMAT" "$DESTINATION/$LATEST"

echo "done."

一応.

このスクリプトを走らせる度に,
DESTINATIONで定義したスペースに,DATE_FORMATと言うディレクトリを作成し,
作ったディレクトリを最新アイテムとして,lnLATESTと言う名前で,symlinkを生成する.

でも作らない笑
File existsエラー.

んなもんです.

何かすみません.

そして実は...
最初に疑ったのは,testコマンドだったりするのです.

おい,どこに行く...

情弱のなせる技.

symlink... ん?(二度見😳)

確認してみます.;

% ll ./bkup
total 0
drwxr-xr-x  2 woowee  staff  64  7  6 20:47 20-47-01
drwxr-xr-x  2 woowee  staff  64  7  6 20:47 20-47-18
drwxr-xr-x  2 woowee  staff  64  7  6 20:47 20-47-39
lrwxr-xr-x  1 woowee  staff  13  7  6 20:47 Latest -> bkup/20-47-01

最後の行.
ファイル属性は,1文字目がl
そしてtargetLatestとsourcebkup/20-47-01->で結ばれている,ということでsymlinkは出来ているっぽい?

ただ.

source側がbkup/20-47-01のまま.

さっっぱり分からない.

自分のレベルだと,まずここまでで,「なぜsymulinkbkup/Latestあるのに,testは識別して削除するロジックに落としてくれないのさ...」となる.

なんとも稚拙な解析力.

「なぜ消さない」

情弱の暴走が発動します.

-eオプション調べる.;

$ test -e bkup/Latest ; echo $?
1

い,...いち..

「存在しません」と判断し,rmの処理に落ちないのは,
正しい振る舞いだったわけですね.

じゃぁ,そのbkup/Latestは何なのさ.

-Lオプションがあるのを思い出した

この作業でリファレンスしたコードは,確か-Lオプションを使っていたはず.

$ test -L bkup/Latest ; echo $?
0

あ.*3

manpageにも書いてますね.

-L file True if file exists and is a symbolic link.

「存在し,シンボリックリンクだったら,真」.

存在も見ている,ってことで良いのでしょうか.
-eが見ている存在と何が違うのだろうか,と何んか附に落ちませんが.

という事で,オプションを大人しく-Lにする.

当該箇所のみ引用しますと,こんな感じです.;

...
# if [[ -e "$DESTINATION/$LATEST" ]] ; then   # -eオプションではなく,
if [[ -L "$DESTINATION/$LATEST" ]] ; then     # -Lオプションを使う
  rm "$DESTINATION/$LATEST"
fi
...

うまく行くみたい.

ln: bkup/Latest: File existsというエラーを吐くことはなく,結果を覗くと.;

% ll bkup/
total 0
drwxr-xr-x  2 woowee  staff  64  7  6 20:47 20-47-01
drwxr-xr-x  2 woowee  staff  64  7  6 20:47 20-47-18
drwxr-xr-x  2 woowee  staff  64  7  6 20:47 20-47-39
drwxr-xr-x  2 woowee  staff  64  7  6 21:00 21-00-07
lrwxr-xr-x  1 woowee  staff  13  7  6 21:00 Latest -> bkup/21-00-07

source_fileの方も,最も新しいbkup/21-00-07からリンクが貼られています.

-eを使っていたときは,ずっと20-47-01でした.

上手く行った?

オプションのようだった.
めでたしめでたし.

どれどれ...と.;

% cd Latest
cd:cd:1: no such file or directory: Latest

ん,ん?

何の気なしに,Finderで覗いて見た.;

f:id:wooweezoowee:20210706231807p:plain:w600

ん?

アイコン,しろ?

とにかく,おかしいのは,わかった.

それは幻です

やっとこの辺りで気付きます.

そのsymlink,実はsymlinkじゃない,と言う,事実.😌

% stat -L bkup/Latest
stat: bkup/Latest: stat: No such file or directory

?...

statの使い方良く分かりません.

% file bkup/Latest
bkup/Latest: broken symbolic link to bkup/05-08-46

fileコマンド,「それ,壊れてますよ」と.

この辺りでやっと気づきました.

testコマンドは,見当違い

testコマンドが,ファイル壊すわけありません笑

"lnコマンド 注意"あたりで検索したら,相対パスのトピックが目に入り.

"lnコマンド 相対パス"とかで調べたら,...出るわ出るわ.

しかも結構前に,語り尽くされた感あり.

ここでも,置いていかれている感に打ちひしがれる.何周遅れなん.prz

そんな感じで

lnコマンドで相対パスを使った場合の問題であることを,やっとここで知るわけです.

#!/bin/bash -eu

SOURCE=""
DESTINATION="bkup"

LATEST="Latest"

readonly DATE_FORMAT=$(date "+%H-%M-%S")

if [[ ! -e "$DESTINATION/$DATE_FORMAT" ]] ; then
  mkdir -p "$DESTINATION/$DATE_FORMAT"
fi

if [[ -e "$DESTINATION/$LATEST" ]] ; then   # 結局 -e オプションでも良い
# if [[ -L "$DESTINATION/$LATEST" ]] ; then
  rm "$DESTINATION/$LATEST"
fi

ln -s "./$DATE_FORMAT" "$DESTINATION/$LATEST" # 問題はここ,source_file 側の定義の仕方

echo "done."

そして.;

f:id:wooweezoowee:20210706231823p:plain:w600

知らなかったなぁ,知らないままlnコマンド使っていたなぁ,交通ルールを知らないまま運転してたようなもんだ...なんぞ思いながら片づけをしていたら.

-rオプションだってさっ

-r オプション最強
この目的のためにあるのが、r オプション

ln -sr で解決
相対パスを自動て解決してくれるのが -r オプション。まじでコレ付けるだけで解決する魔法のオプション

これ見て胸が膨らんだのですが,どうやらlinuxの話らしく,こちらのmanpageにはrオプションの記載はありませんでした.BSDにはないみたいです.

はいおしまい.

結構書いたな,おい.

*1:'man ln'や,より優れた他のサイト,エントリにお任せするとしまして.

*2:実は今回書いておきたかったのは,こちらの方だったり...

*3:なぜ,自分のコードは「-L」ではなく,「-e」にしたか.
「在るか否か」を判定するので,「symlinkかどうか」という切り口で判断するのは,どうも気持ち悪いな,と感じたからです.そんな程度の根拠.