उन बड़ी फ़ाइलों को खोजें और निकालें जो खुली हैं लेकिन हटा दी गई हैं


119

कोई ऐसी बड़ी फ़ाइल कैसे खोजता है जिसे हटा दिया गया है लेकिन अभी भी एक आवेदन में खुला है? कोई ऐसी फ़ाइल कैसे निकाल सकता है, भले ही यह एक प्रक्रिया है?

स्थिति यह है कि हम एक ऐसी प्रक्रिया चला रहे हैं जो एक लॉग फ़ाइल को एक भयानक दर पर भर रही है। मुझे इसका कारण पता है, और मैं इसे ठीक कर सकता हूं। तब तक, मैं प्रक्रिया को बंद किए बिना लॉग फ़ाइल को rm या खाली करना चाहूंगा।

बस कर rm output.logकेवल फ़ाइल के संदर्भों को हटाता है, लेकिन यह डिस्क पर स्थान पर कब्जा करना जारी रखता है जब तक कि प्रक्रिया समाप्त नहीं हो जाती। इससे भी बदतर: rmआईएनजी के बाद अब मेरे पास यह खोजने का कोई तरीका नहीं है कि फाइल कहाँ है या यह कितना बड़ा है! क्या फ़ाइल खोजने का कोई तरीका है, और संभवतः इसे खाली कर दें, भले ही यह अभी भी किसी अन्य प्रक्रिया में खुला हो?

मैं विशेष रूप से लिनक्स आधारित ऑपरेटिंग सिस्टम जैसे डेबियन या आरएचईएल का उल्लेख करता हूं।


2
यदि आप पिड जानते हैं तो आप lsof -p <pid>इसकी खुली फ़ाइलों और उनके आकारों को सूचीबद्ध करने के लिए उपयोग कर सकते हैं। हटाई गई फ़ाइल के पास एक (deleted)अगला होगा। हटाई गई फ़ाइल /proc/<pid>/fd/1संभवतः पर लिंक की जाएगी । मैं नहीं जानता कि कैसे एक प्रक्रिया को समाप्त किए बिना इसकी फाइल डिस्क्रिप्टर पर लिखना बंद कर दिया जाए। मुझे लगता है कि यह प्रक्रिया पर निर्भर करेगा।
donothingsuccessfully

धन्यवाद। सभी rmएड फ़ाइलों के PID कैसे प्राप्त हो सकते हैं जो अभी भी खुले हैं?
dotancohen

@donothingsuccessfully lsof द्वारा रिपोर्ट किया गया "डिलीट" टैग सोलारिस विशिष्ट है, वास्तव में सोलारिस 10 या बाद में। ओपी ने निर्दिष्ट नहीं किया कि वह किस ऑपरेटिंग सिस्टम का उपयोग कर रहा है। @dotancohen Solaris पर आप डिलीट किए गए खोज के लिए lsof के आउटपुट को पाइप कर सकते हैं, जैसे lsof | grep "(deleted)"। जब कोई हटाए गए फ़ाइल को खोलने की कोई और प्रक्रिया नहीं होती है, तो कर्नेल इनोड और डिस्क ब्लॉक को मुक्त कर देगा। प्रक्रियाओं में "हैंडलर" नहीं होते हैं, जिसके द्वारा उन्हें सूचित किया जा सकता है कि डिस्क से एक खुली, अनिवार्य रूप से लॉक की गई फ़ाइल को हटा दिया गया है।
जोहान

2
@ जोहान, lsof | grep '(deleted)'लिनक्स पर भी काम करता है। लिनक्स पर, आपको फ़ाइल विलोपन के बारे में सूचित किया जा सकता है (यहां तक ​​कि ऐसी फाइलें जो पहले से ही किसी भी निर्देशिका में / proc / /-pid / fd के अलावा अन्य किसी भी प्रविष्टि में नहीं हैं) inotify तंत्र (IN_DELETE_SELF घटना) के साथ
Stéphane Chazelas

मैंने somefileइसे VIM में बनाया और खोला, फिर rmइसे किसी अन्य बैश प्रक्रिया में एड करें। मैं तब भागता हूं lsof | grep somefileऔर यह वहां नहीं है, भले ही फ़ाइल वीआईएम में खुली हो।
डॉटनचेन

जवाबों:


141

यदि आप अपने एप्लिकेशन को नहीं मार सकते हैं, तो आप अंतरिक्ष को पुनः प्राप्त करने के लिए लॉग फ़ाइल को हटाने के बजाय छोटा कर सकते हैं। यदि फ़ाइल एपेंड मोड में नहीं खुली थी (साथ में O_APPEND), तो फ़ाइल अगली बार आवेदन करने से पहले लिखी गई बड़ी दिखाई देगी (हालांकि प्रमुख भाग विरल के साथ और देखने में ऐसा लगता है मानो इसमें NUL बाइट्स हों), लेकिन स्थान फिर से प्राप्त किया गया है (जो कि Apple OS / X पर HFS + फ़ाइल सिस्टम पर लागू नहीं होता है, जो विरल फ़ाइलों का समर्थन नहीं करते हैं)।

इसे छोटा करने के लिए:

: > /path/to/the/file.log

यदि यह लिनक्स पर पहले से ही हटा दिया गया था, तब भी आप इसे कर सकते हैं:

: > "/proc/$pid/fd/$fd"

$pidउस प्रक्रिया की प्रक्रिया आईडी कहां है जिसमें फ़ाइल खोली गई है, और $fdएक फ़ाइल विवरणक है जिसे उसने खोला है (जिसके साथ आप जांच कर सकते हैं lsof -p "$pid"

यदि आप पिड नहीं जानते हैं, और हटाई गई फ़ाइलों की तलाश कर रहे हैं, तो आप कर सकते हैं:

lsof -nP | grep '(deleted)'

lsof -nP +L1, जैसा कि @ user75021 द्वारा उल्लेख किया गया है, एक और भी बेहतर (अधिक विश्वसनीय और अधिक पोर्टेबल) विकल्प है (सूची फ़ाइलें जिनके पास 1 से कम लिंक है)।

या (लिनक्स पर):

find /proc/*/fd -ls | grep  '(deleted)'

या के साथ बड़े लोगों को खोजने के लिए zsh:

ls -ld /proc/*/fd/*(-.LM+1l0)

एक विकल्प, यदि एप्लिकेशन गतिशील रूप से जुड़ा हुआ है, तो डिबगर को इसके साथ संलग्न करना है और इसे close(fd)एक नए द्वारा कॉल करना है open("the-file", ....)


1
वहाँ भी एक truncateआदेश है कि एक ही बात अधिक स्पष्ट रूप से करता है।
तोबू

1
@dotancohen स्टीफन ने जानकारी को संपादित करने के लिए संपादित किया कि यह कैसे करना है जब पिड ज्ञात नहीं है।
दीदी कोहेन

1
@OlivierDulac, lsofसंभवत: एक पोर्टेबल समाधान के सबसे नज़दीकी होने जा रहा है जिसे आप खुली फ़ाइलों को सूचीबद्ध करने के लिए प्राप्त कर सकते हैं। डिबगर एप्रोच को पैरों के नीचे से बंद करने का तरीका काफी पोर्टेबल होना चाहिए।
स्टीफन चेज़लस

2
@ स्टेफ़ेनचेज़लस: धन्यवाद। मुझे सभी पीआईडी ​​को सूचीबद्ध करने का एक तरीका मिला, जिसमें प्रत्येक विभाजन पर एक फ़ाइल खुली है: df -k | awk 'NR>1 { print $NF }' | xargs fuser -Vud (और फिर अपराधियों को संकेत भेजने के लिए उन्हें एफडी जारी करने के लिए मजबूर करना आसान है)
ओलिवियर दुलक

6
आप भी इस्तेमाल कर सकते हैं lsof +L1। Lsof मैन पेज से: "फ़ॉर्म का एक विनिर्देश +L1खुली हुई फ़ाइलों का चयन करेगा जिन्हें अनलिंक किया गया है। प्रपत्र का एक विनिर्देश +aL1 <file_system>निर्दिष्ट फ़ाइल सिस्टम पर अनलिंक की गई खुली फ़ाइलों का चयन करेगा।" यह थोड़ा और अधिक विश्वसनीय होना चाहिए।
सिंक्रो

30

क्विकार्टार्ट यहां देखें: lsofक्विकार्टार्ट

मुझे आश्चर्य है कि किसी ने भी lsof क्विकस्टार्ट फ़ाइल (lsof के साथ शामिल) का उल्लेख नहीं किया है। अनुभाग "3.a" दिखाता है कि कैसे खुली, अनलिंक की गई फ़ाइलों को खोजें:

lsof -a +L1 *mountpoint*

उदाहरण के लिए:

[root@enterprise ~]# lsof -a +L1 /tmp
COMMAND   PID   USER   FD   TYPE DEVICE    SIZE NLINK  NODE NAME
httpd    2357 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
mysqld   2588  mysql    4u   REG 253,17      52     0  1495 /tmp/ibY0cXCd (deleted)
mysqld   2588  mysql    5u   REG 253,17    1048     0  1496 /tmp/ibOrELhG (deleted)
mysqld   2588  mysql    6u   REG 253,17       0     0  1497 /tmp/ibmDFAW8 (deleted)
mysqld   2588  mysql    7u   REG 253,17       0     0 11387 /tmp/ib2CSACB (deleted)
mysqld   2588  mysql   11u   REG 253,17       0     0 11388 /tmp/ibQpoZ94 (deleted)
httpd    3457   root   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8437 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8438 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8439 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8440 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8441 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8442 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8443 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8444 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   16990 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   19595 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   27495 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   28142 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   31478 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)

रेड हैट सिस्टम पर क्विक-स्टार्ट फाइल की स्थानीय प्रति खोजने के लिए, मैं आमतौर पर ऐसा करता हूं:

[root@enterprise ~]# locate -i quickstart |grep lsof
/usr/share/doc/lsof-4.78/00QUICKSTART

... या यह:

[root@enterprise ~]# rpm -qd lsof
/usr/share/doc/lsof-4.78/00.README.FIRST
/usr/share/doc/lsof-4.78/00CREDITS
/usr/share/doc/lsof-4.78/00DCACHE
/usr/share/doc/lsof-4.78/00DIALECTS
/usr/share/doc/lsof-4.78/00DIST
/usr/share/doc/lsof-4.78/00FAQ
/usr/share/doc/lsof-4.78/00LSOF-L
/usr/share/doc/lsof-4.78/00MANIFEST
/usr/share/doc/lsof-4.78/00PORTING
/usr/share/doc/lsof-4.78/00QUICKSTART
/usr/share/doc/lsof-4.78/00README
/usr/share/doc/lsof-4.78/00TEST
/usr/share/doc/lsof-4.78/00XCONFIG
/usr/share/man/man8/lsof.8.gz

1

यह फ़ाइल सिस्टम ड्राइवर पर निर्भर है कि वास्तव में आवंटित स्थान को मुक्त कर दिया जाए, और यह आमतौर पर केवल एक बार होगा जब सभी फ़ाइल विवरणकर्ता उस फ़ाइल का संदर्भ देते हैं। इसलिए आप वास्तव में स्थान को पुनः प्राप्त नहीं कर सकते, जब तक कि आप एप्लिकेशन को फ़ाइल बंद न करें। जिसका अर्थ है कि या तो इसे समाप्त करना या इसके साथ एक डिबगर में "थोड़ा" खेलना (जैसे फ़ाइल को बंद करना और सुनिश्चित करना कि इसे फिर से नहीं लिखा गया है, या /dev/nullइसके बजाय खोलना है )। या आप कर्नेल को हैक कर सकते हैं, लेकिन मैं उसके खिलाफ सलाह दूंगा।

फ़ाइल को ट्रंच करना, जैसा कि स्टीफन सुझाव देता है, मदद कर सकता है, लेकिन वास्तविक परिणाम आपके फ़ाइल सिस्टम पर भी निर्भर करेगा (उदाहरण के लिए पूर्व-आवंटित ब्लॉक संभवतः किसी भी मामले में फ़ाइल बंद करने के बाद ही मुक्त हो जाएगा)।

इस व्यवहार के पीछे तर्क यह है कि कर्नेल को यह नहीं पता होगा कि डेटा अनुरोधों के साथ क्या करना है (दोनों पढ़ना और लिखना, लेकिन पढ़ना वास्तव में अधिक महत्वपूर्ण है) ऐसी फाइल को लक्षित करना।


2
जैसा कि लिनक्स अधिकांश फ़ाइल सिस्टम पर विरल फ़ाइलों का समर्थन करता है , व्यवहार अच्छी तरह से परिभाषित है और डिस्क ड्राइवर वास्तव में डिस्क स्थान को मुक्त कर सकता है। मैंने इसे ext3 और ext4 के लिए परीक्षण किया है, और यह स्टीफन की तरह काम करता है।
जोफेल

1
आप क्या कहते हैं कि किसी फ़ाइल को काट-छाँट करने से प्रचारित ब्लॉक पुनः प्राप्त नहीं होंगे? ट्रंकटिंग का तात्पर्य डेटा से संबंधित है, मुझे इस बात से कोई मतलब नहीं है कि इसके साथ कोई अस्पष्टता है।
स्टीफन चेज़लस

1
फ़ाइल सिस्टम बाद में समय बचाने के लिए आवंटित ब्लॉकों को रख सकता है (खासकर यदि फ़ाइल अभी भी खुली हुई है), खासकर जब यह ट्रंक करने से पहले काफी बड़ा था। कम से कम XFS ऐसा लगता है।
पीटरफ

धन्यवाद पीटर। मुझे खुशी है कि आप इस पोस्ट में "क्यों" को संबोधित करते हैं।
डॉटनचेन

2
जहां तक ​​मैं बता सकता हूं, खुली फाइलों को रौंदने से एक्सएफएस पर भी जगह मिल जाती है। fallocateलिनक्स 4.9 पर आवंटित सामान्य फ़ाइल और फ़ाइल दोनों के साथ परीक्षण किया गया । क्या आप कृपया स्पष्ट कर सकते हैं कि किसी फाइल को रौंदने वाली फाइलसिस्टम और स्थिति क्या स्पेस को पुनः प्राप्त नहीं करती है?
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.