मुझे अपेक्षा होगी
find . -delete
वर्तमान निर्देशिका को हटाने के लिए, लेकिन यह नहीं है। क्यों नहीं?
find . -print
।
cd ..; rm -r dir
एक अन्य शेल के साथ काफी स्पष्ट शब्दार्थों के साथ कर सकते हैं ...
मुझे अपेक्षा होगी
find . -delete
वर्तमान निर्देशिका को हटाने के लिए, लेकिन यह नहीं है। क्यों नहीं?
find . -print
।
cd ..; rm -r dir
एक अन्य शेल के साथ काफी स्पष्ट शब्दार्थों के साथ कर सकते हैं ...
जवाबों:
सदस्यों के findutils
बारे में पता है , यह * BSD के साथ संगत के लिए है:
कारणों में से एक है कि हम "" को हटाना छोड़ देते हैं। * बीएसडी के साथ अनुकूलता के लिए, जहां यह कार्रवाई हुई।
समाचार findutils स्रोत कोड शो में है कि वे व्यवहार रखने का फैसला किया:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[अद्यतन करें]
चूंकि यह प्रश्न गर्म विषय में से एक बन गया है, इसलिए मैं FreeBSD स्रोत कोड में गोता लगाता हूं और अधिक ठोस कारण बताता हूं।
आइए FreeBSD का यूटिलिटी सोर्स कोड देखें :
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);
}
...
जैसा कि आप देख सकते हैं, अगर यह डॉट और डॉट-डॉट को फ़िल्टर नहीं करता है, तो यह rmdir()
POSIX द्वारा परिभाषित C फ़ंक्शन तक पहुंच जाएगा unistd.h
।
एक साधारण परीक्षण करें, डॉट / डॉट-डॉट तर्क के साथ rmdir -1 लौट आएगा:
printf("%d\n", rmdir(".."));
आइए एक नज़र डालते हैं कि POSIX rmdir का वर्णन कैसे करते हैं :
यदि पथ तर्क उस पथ को संदर्भित करता है जिसका अंतिम घटक या तो डॉट या डॉट-डॉट है, तो rmdir () विफल हो जाएगा।
कोई कारण नहीं बताया गया shall fail
।
मैंने पाया rename
कि कुछ reaso n समझाएँ :
चक्रीय फ़ाइल सिस्टम पथ को रोकने के लिए नाम या डॉट-डॉट का नामकरण निषिद्ध है।
चक्रीय फ़ाइल सिस्टम पथ ?
मैं सी प्रोग्रामिंग लैंग्वेज (2 डी संस्करण) को देखता हूं और निर्देशिका विषय की खोज करता हूं, आश्चर्यजनक रूप से मैंने पाया कि कोड समान है :
if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
continue;
और टिप्पणी!
प्रत्येक निर्देशिका में हमेशा "," और उसके माता-पिता, ".." नामक प्रविष्टियाँ होती हैं; इन्हें छोड़ दिया जाना चाहिए, या प्रोग्राम हमेशा के लिए लूप हो जाएगा ।
"हमेशा के लिए लूप" , यह ऊपर दिए गए "चक्रीय फ़ाइल सिस्टम पथ" केrename
रूप में वर्णन करने के तरीके के समान है।
मैं कोड को थोड़ा संशोधित करता हूं और इस उत्तर के आधार पर काली लिनक्स में इसे चलाने के लिए :
#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);
}
चलो देखते हैं:
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$
यह सही ढंग से काम करता है, अब क्या होगा अगर मैं continue
निर्देश पर टिप्पणी करता हूं :
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$
जैसा कि आप देख सकते हैं, मुझे इस असीम लूप प्रोग्राम को मारने के लिए Ctrl+ Cका उपयोग करना होगा।
'..' निर्देशिका ने अपनी पहली प्रविष्टि '..' और लूप को हमेशा के लिए पढ़ा।
निष्कर्ष:
जीएनयू * बीएसडी में उपयोगिता findutils
के साथ संगत करने का प्रयास करता है ।find
find
* बीएसडी में उपयोगिता आंतरिक रूप से rmdir
POSIX- अनुरूप C फ़ंक्शन का उपयोग करती है जो डॉट / डॉट-डॉट की अनुमति नहीं है।
rmdir
डॉट / डॉट-डॉट की अनुमति नहीं देने का कारण चक्रीय फ़ाइल सिस्टम पथ को रोकना है।
K & R द्वारा लिखित C प्रोग्रामिंग लैंग्वेज इस बात का उदाहरण दिखाती है कि कैसे डॉट / डॉट-डॉट हमेशा के लिए लूप प्रोग्राम को बढ़ावा देगा।
क्योंकि आपका find
कमांड .
परिणाम के रूप में लौटता है । के जानकारी पृष्ठ से rm
:
किसी फ़ाइल को निकालने का कोई प्रयास जिसका अंतिम फ़ाइल नाम घटक है '।' या '..' को बिना किसी संकेत के अस्वीकार कर दिया गया है, जैसा कि POSIX द्वारा अनिवार्य है।
तो, ऐसा लगता है कि find
इस मामले में बस पोसिक्स के नियमों से चिपक जाता है।
/var/log
और आप उस रूट को सोच रहे थे, यह सोचकर कि यह सभी उपखंडों को हटा देगा और वर्तमान निर्देशिका को भी हटा देगा?
man
पृष्ठ find
कहता है: "यदि निष्कासन विफल हुआ, तो एक त्रुटि संदेश जारी किया जाता है।" कोई त्रुटि क्यों नहीं छपी है?
mkdir foo && cd foo && rmdir $(pwd)
:। यह काम नहीं कर रहा है .
(या ..
) निकाल रहा है।
Rmdir सिस्टम कॉल EINVAL के साथ विफल हो जाती है यदि इसके तर्क पथ का अंतिम घटक है "."
। यह http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html पर प्रलेखित है
और व्यवहार के लिए तर्क है:
Pathname / dot को हटाने का अर्थ स्पष्ट नहीं है, क्योंकि हटाए जाने के लिए मूल निर्देशिका में फ़ाइल (निर्देशिका) का नाम स्पष्ट नहीं है, विशेष रूप से एक निर्देशिका के लिए कई लिंक की उपस्थिति में।
जबकि While, और थॉमस ने पहले ही इस पर अच्छे उत्तर दे दिए थे, मुझे लगता है कि उनके उत्तर यह बताना भूल गए कि इस व्यवहार को पहले स्थान पर क्यों लागू किया गया था।
आपके find . -delete
उदाहरण में वर्तमान निर्देशिका को हटाना बहुत तार्किक और समझदार लगता है। पर विचार करें:
$ find . -name marti\*
./martin
./martin.jpg
[..]
क्या आप .
अभी भी तार्किक और समझदार हैं?
एक गैर-रिक्त निर्देशिका को हटाना एक त्रुटि है - इसलिए आप इसके साथ डेटा को खोने की संभावना नहीं रखते हैं find
(हालांकि आप के साथ कर सकते हैं rm -r
) - लेकिन आपके शेल में इसकी वर्तमान कार्यशील निर्देशिका एक निर्देशिका के लिए सेट होगी जो अब मौजूद नहीं है, जिससे कुछ भ्रमित हो सकता है और आश्चर्यजनक व्यवहार:
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
नहीं वर्तमान निर्देशिका हटाने का अच्छा इंटरफेस डिजाइन और कम से कम आश्चर्य की बात है के सिद्धांत का अनुपालन।