Düzenli bir dosyayı sembolik bağlantıdan ayırt etmek


22

Normal bir dosyayı sembolik bağlantıdan ayırt etmek için gerekli olan bash betiğini yazıyorum. Bunu if / test ifadesiyle yapabileceğimi düşündüm, ancak beklediğim gibi çalışmıyor:

$ touch regular_file
$ test -f regular_file; echo $?
0
$ test -h regular_file; echo $?
1
$ ln -s regular_file symlink
$ test -h symlink; echo $?
0
$ test -f symlink; echo $?
0

Neden? Ve, nasıl düzgün yapabilirim?

Yanıtlar:


20

Görünüşe göre testlerini biraz karıştırıyorsun. Her iki testi de uygulamanıza gerek yoktur, bu durumda ihtiyacınız olan -htek şey, dosyanın bir bağlantı olup olmadığını söyleyendir.

test -h file && echo "is symlink" || echo "is regular file"

-fNesne bir dosya olup olmadığı test sadece size söyler. Bu 0, bir dizin veya aygıt düğümü veya bir dizine bir işaret simgesi olsaydı geri dönerdi, ancak 1bir dosyaya bir işaret simgesi döndürür .

Ayrıca, bunun bir dizinden ziyade bir dosyaya bağlanıp bağlanmadığını bilmeniz gerekiyorsa, her iki testin sonuçlarını da biraz mantıkla birleştirmeniz gerekir.


I dokümanlar anlaşıldığı gibi, arasındaki fark -eve -fbu edilmiştir -e(herhangi bir tip), bir dosya mevcut olup olmadığını bilmek için kullanılmıştır ve -fdosya mevcut ve normal bir dosya olup olmadığını test etmek için özel olarak oldu. Görünüşe göre "normal bir dosya" nın ne olduğunu yanlış anladım ..
Nupraptor

1
@Nupraptor: Evet, sen doktorları yanlış anladın. Bir bağlantı, bir dosyanın olabileceği diğer düğüm türlerinden bazılarının aksine normal bir dosya olarak kabul edilir (blok-cihaz düğümü, karakter-aygıt düğümü, dizin vb.). Hangi tür TİP'in dosya olduğunu bilmek istiyorsanız, -hsembolik bağlantılarda, -padlandırılmış borularda olduğu gibi dosya türüne özgü bir test çalıştırmanız gerekir .
Caleb

Öyleyse, bir dosyanın normal olmayan bir dosya olup olmadığını, ne de boru hattı, bir sembolik bağlantı vb. Olduğunu nasıl test ederim? Bunun için başka bir soru açmalı mıyım?
Nupraptor

@Nupraptor: Tek garip durum, normal bir dosyaya bağlanan bir sembolik bağlantıdır. Aksi takdirde, normal bir dosya olarak test ederse, normal bir dosyadır.
David Schwartz

3
test -f dizini 1 değil 0 döndürür: test -f. ; Eko mu? (çıkış 1)
polinom

7

@Caleb, betiğin sadece sembolik bağlantı için sınamalarını sağlama konusunda doğrudur. Ancak neden hakkında bırakılan kısmı merak ettim. Eğer coreutils kaynak koduna bakarsanız ve testin çıktısını alırsanız, sembolik link testini çalıştırdığınızda lstat kullandığını ve -f testini kullanıyorsanız aslında sembolik bağlantıyı takip eden 'stat' dediğini görürsünüz:

$ ln -s varnish_config XXX
$ strace -s 2000 test -L XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-L", "XXX"], [/* 47 vars */]) = 0
lstat("XXX", {st_mode=S_IFLNK|0777, st_size=14, ...}) = 0

$ strace -s 2000 test -L varnish_config 2>&1 | grep varnish
execve("/usr/bin/test", ["test", "-L", "varnish_config"], [/* 47 vars */]) = 0
lstat("varnish_config", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

$ strace -s 2000 test -f XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-f", "XXX"], [/* 47 vars */]) = 0
stat("XXX", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

Stat man sayfasından:

   stat() stats the file pointed to by path and fills in buf.

   lstat() is identical to stat(), except that if path is a symbolic link,
   then the link itself is stat-ed, not the file that it refers to.

Bu, -f sınamasının, belirtilen dosya adı normal bir dosyaya veya normal bir dosyanın kendisine verilen bir bağlantı olduğu sürece gerçekleşeceği anlamına gelir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.