Beklemek isterim
find . -delete
Geçerli dizini silmek için, ancak değil. Neden olmasın?
find . -print
.
cd ..; rm -r dir
Oldukça net bir anlambilim ile başka bir kabuk ile yapabilirsiniz ...
Beklemek isterim
find . -delete
Geçerli dizini silmek için, ancak değil. Neden olmasın?
find . -print
.
cd ..; rm -r dir
Oldukça net bir anlambilim ile başka bir kabuk ile yapabilirsiniz ...
Yanıtlar:
findutils
Farkında olan üyeleri, * BSD ile uyumlu için:
"" Silme işleminin atlanmasının sebeplerinden biri. bu eylemin kaynaklandığı * BSD ile uyumluluk içindir.
HABER onlar davranışlarını tutmaya karar findutils kaynak kod gösterir:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[GÜNCELLEŞTİRME]
Bu soru sıcak konulardan biri olduğu için FreeBSD kaynak koduna daldım ve daha inandırıcı bir neden buldum.
FreeBSD'nin find yardımcı programı kaynak kodunu görelim :
int
f_delete(PLAN *plan __unused, FTSENT *entry)
{
/* ignore these from fts */
if (strcmp(entry->fts_accpath, ".") == 0 ||
strcmp(entry->fts_accpath, "..") == 0)
return 1;
...
/* rmdir directories, unlink everything else */
if (S_ISDIR(entry->fts_statp->st_mode)) {
if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
warn("-delete: rmdir(%s)", entry->fts_path);
} else {
if (unlink(entry->fts_accpath) < 0)
warn("-delete: unlink(%s)", entry->fts_path);
}
...
Gördüğünüz gibi, nokta ve nokta noktasını filtrelemezse, POSIX'in rmdir()
tanımladığı C işlevine erişir unistd.h
.
Basit bir test yapın, rmdir ile dot / dot-dot argümanı -1 döndürür:
printf("%d\n", rmdir(".."));
POSIX'in rmdir'i nasıl tanımladığına bir bakalım :
Path argümanı, son bileşeni nokta ya da nokta-nokta olan bir yola atıfta bulunursa, rmdir () başarısız olur.
Sebebi neden yoktu shall fail
.
Bulduğum rename
bazı reaso açıklamak n:
Döngüsel dosya sistemi yollarını önlemek için nokta veya nokta noktanın yeniden adlandırılması yasaktır.
Döngüsel dosya sistemi yolları ?
C Programlama Dili'ne (2. Baskı) baktım ve dizin konusunu araştırdım, şaşırtıcı bir şekilde kodun benzer olduğunu gördüm :
if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
continue;
Ve yorum!
Her dizin daima kendisi için "." Adı verilen girişleri ve onun üst öğesi ".."; bunlar atlanmalıdır, aksi takdirde program sonsuza kadar döngülenir .
"sonsuza kadar döngü" , bu nasıl gibi aynıdır rename
olarak tarif "döngüsel dosya sistemi yolları" yukarıda.
Kodu biraz değiştirip bu cevabı temel alarak Kali Linux'ta çalışmasını sağlamak için :
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
void fsize(char *);
void dirwalk(char *, void (*fcn)(char *));
int
main(int argc, char **argv) {
if (argc == 1)
fsize(".");
else
while (--argc > 0) {
printf("start\n");
fsize(*++argv);
}
return 0;
}
void fsize(char *name) {
struct stat stbuf;
if (stat(name, &stbuf) == -1 ) {
fprintf(stderr, "fsize: can't access %s\n", name);
return;
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
dirwalk(name, fsize);
printf("%81d %s\n", stbuf.st_size, name);
}
#define MAX_PATH 1024
void dirwalk(char *dir, void (*fcn)(char *))
{
char name[MAX_PATH];
struct dirent *dp;
DIR *dfd;
if ((dfd = opendir(dir)) == NULL) {
fprintf(stderr, "dirwalk: can't open %s\n", dir);
return;
}
while ((dp = readdir(dfd)) != NULL) {
sleep(1);
printf("d_name: S%sG\n", dp->d_name);
if (strcmp(dp->d_name, ".") == 0
|| strcmp(dp->d_name, "..") == 0) {
printf("hole dot\n");
continue;
}
if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name)) {
printf("mocha\n");
fprintf(stderr, "dirwalk: name %s/%s too long\n",
dir, dp->d_name);
}
else {
printf("ice\n");
(*fcn)(dp->d_name);
}
}
closedir(dfd);
}
Bakalım:
xb@dnxb:/test/dot$ ls -la
total 8
drwxr-xr-x 2 xiaobai xiaobai 4096 Nov 20 04:14 .
drwxr-xr-x 3 xiaobai xiaobai 4096 Nov 20 04:14 ..
xb@dnxb:/test/dot$
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
d_name: S.G
hole dot
4096 .
xb@dnxb:/test/dot$
Doğru çalışıyor, şimdi continue
talimatı yorumlasam ne olur :
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
^C
xb@dnxb:/test/dot$
Gördüğünüz gibi, bu sonsuz döngüsel programı öldürmek için Ctrl+ kullanmam Cgerekiyor.
'..' dizini ilk girişi olan '..' 'ı okur ve sonsuza dek tekrar eder.
Sonuç:
GNU * BSD'deki yardımcı programla findutils
uyumlu olmaya çalışır .find
find
* BSD'deki yardımcı program dahili olarak rmdir
nokta / nokta-noktaya izin verilmeyen POSIX uyumlu C işlevini kullanır .
rmdir
Nokta / nokta-noktaya izin vermeme nedeni döngüsel dosya sistemi yollarını önlemektir.
K&R tarafından yazılan C Programlama Dili , nokta / nokta-noktanın sonsuza dek döngü programına nasıl gideceği örneğini gösterir.
Çünkü find
emriniz .
sonuç olarak döner . Bilgi sayfasından rm
:
Son dosya adı bileşeni '.' Olan bir dosyayı kaldırma girişimi. veya '..' POSIX tarafından zorunlu tutulduğu şekilde herhangi bir talepte bulunulmaksızın reddedilir.
Yani, find
bu durumda sadece POSIX kurallarına sadık kalıyor gibi görünüyor .
/var/log
ve siz onu kök olarak koştuysanız, tüm alt dizinleri sileceğini ve mevcut dizini de kaldırdığını düşünerek?
man
sayfada find
yazıyor: "Kaldırma işlemi başarısız olursa bir hata mesajı verilir." Neden hata yazdırılmıyor?
mkdir foo && cd foo && rmdir $(pwd)
. Çalışmıyor kaldırma .
(veya ..
).
Argüman yolunun son bileşeni ise rmdir sistemi çağrısı EINVAL ile başarısız olur "."
. Http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html adresinde belgelenmiştir
ve bu davranışın gerekçesi şöyledir:
Pathname / dot 'un silinmesinin anlamı belirsizdir, çünkü kaldırılacak olan ana dizindeki dosyanın (dizin) ismi, özellikle bir dizine birden fazla bağlantı olması durumunda net değildir.
皞 皞 ve Thomas zaten bu konuda iyi cevaplar verirken, cevaplarının bu davranışın neden ilk başta uygulandığını açıklamayı unuttuğunu hissediyorum .
Örnekte find . -delete
, geçerli dizini silmek oldukça mantıklı ve aklı başında geliyor. Ancak şunu düşünün:
$ find . -name marti\*
./martin
./martin.jpg
[..]
Silme .
hala mantıklı ve aklı başında geliyor mu?
Boş olmayan bir dizini silmek bir hatadır - bu nedenle find
(bununla birlikte rm -r
) bununla veri kaybetme ihtimaliniz yoktur - ancak kabuğunuzun mevcut çalışma dizini artık mevcut olmayan bir dizine ayarlanmış ve kafa karıştırıcı olabilir. ve şaşırtıcı davranış:
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
Değil Geçerli dizini silme sadece az sürpriz prensibi ile iyi arayüz tasarımı ve uygun olduğu görülmüştür.