फ़ाइल ले जाएँ, लेकिन केवल अगर यह बंद है


10

मैं बंद होते ही बाहरी प्रक्रिया द्वारा बनाई गई बड़ी फ़ाइल को स्थानांतरित करना चाहता हूं।

क्या यह टेस्ट कमांड सही है?

if lsof "/file/name"
then
        # file is open, don't touch it!
else
        if [ 1 -eq $? ]
        then
                # file is closed
                mv /file/name /other/file/name
        else
                # lsof failed for some other reason
        fi
fi

संपादित करें: फ़ाइल एक डेटासेट का प्रतिनिधित्व करती है और मुझे इसे स्थानांतरित करने के लिए पूरा होने तक इंतजार करना होगा ताकि कोई अन्य प्रोग्राम इस पर कार्य कर सके। इसलिए मुझे यह जानना होगा कि क्या फ़ाइल के साथ बाहरी प्रक्रिया की जाती है।


3
साइड नोट: एक बार फाइल खोलने के बाद, प्रोसेस फाइल डिस्क्रिप्टर और इनकोड डेटा को मैनिपुलेट करने के लिए उपयोग करती है। पथ को बदलना (यानी फ़ाइल को स्थानांतरित करना) प्रक्रिया को बहुत अधिक परेशानी नहीं देगा।
जॉन डब्ल्यूएच स्मिथ

2
क्या बाहरी प्रक्रिया पर आपका कोई नियंत्रण है? बाहरी प्रक्रिया के लिए क्या यह संभव होगा कि एक अस्थायी फ़ाइल बनाई जाए और एक बार फ़ाइल लिखने के बाद उसका नाम बदल दिया जाए?
जेनी डी

@ जेनीडी मैंने कुछ जांच की और यह सच है। मुझे बिल्कुल भी ज़रूरत नहीं है कि मुझे यह lsofजांचने की ज़रूरत है कि फ़ाइल एक्सटेंशन नहीं है .tmp। जो इसे तुच्छ बनाता है। हालांकि मुझे खुशी है कि मैं अपने प्रश्न पूछा के बाद से मैं के बारे में थोड़ा सीखा हूँ lsofऔर inotifyऔर सामान।
पीटर कोवाक

@PeterKovac मैंने उनके बारे में और भी सीखा, जवाब पढ़ने से, इसलिए मुझे बहुत खुशी है कि आपने यह पूछा।
जेनी डी

@JohnWHSmith - यदि फ़ाइल को एक ही फाइल सिस्टम में ले जाना सामान्य रूप से सही है, अगर वह फाइल को एक नए फाइल सिस्टम में ले जाता है, इससे पहले कि लेखक ने इसे लिखना समाप्त कर दिया है, तो वह कुछ डेटा खो देगा।
जॉनी

जवाबों:


11

से lsofआदमी पेज

यदि कोई त्रुटि का पता चला है तो Lsof एक (1) देता है, जिसमें कमांड नाम, फ़ाइल नाम, इंटरनेट पते या फाइलें, लॉगिन नाम, एनएफएस फाइलें, पीआईडी, पीजीआईडी, या यूआईडी का पता लगाने में विफलता सहित यह सूची करने के लिए कहा गया था। यदि -V विकल्प निर्दिष्ट किया जाता है, तो lsof उन खोज आइटमों को इंगित करेगा जो इसे सूचीबद्ध करने में विफल रहे।

ताकि यह सुझाव दिया जाए कि आपके lsof failed for some other reasonखंड को कभी निष्पादित नहीं किया जाएगा।

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

यदि आपको फ़ाइल के साथ आपकी बाहरी प्रक्रिया समाप्त होने तक वास्तव में प्रतीक्षा करने की आवश्यकता है, तो आप बार-बार मतदान के बजाय एक कमांड का उपयोग करना बेहतर समझते हैं। लिनक्स पर, आप इसके लिए उपयोग कर सकते हैं inotifywait। उदाहरण के लिए:

 inotifywait -e close_write /path/to/file

यदि आपको उपयोग करना चाहिए lsof(शायद पोर्टेबिलिटी के लिए), तो आप कुछ इस तरह की कोशिश कर सकते हैं:

until err_str=$(lsof /path/to/file 2>&1 >/dev/null); do
  if [ -n "$err_str" ]; then
    # lsof printed an error string, file may or may not be open
    echo "lsof: $err_str" >&2

    # tricky to decide what to do here, you may want to retry a number of times,
    # but for this example just break
    break
  fi

  # lsof returned 1 but didn't print an error string, assume the file is open
  sleep 1
done

if [ -z "$err_str" ]; then
  # file has been closed, move it
  mv /path/to/file /destination/path
fi

अपडेट करें

जैसा कि नीचे @JohnWHSmith ने उल्लेख किया है , सबसे सुरक्षित डिज़ाइन हमेशा lsofऊपर दिए गए लूप का उपयोग करेगा क्योंकि यह संभव है कि एक से अधिक प्रक्रिया में फ़ाइल लिखने के लिए खुली होगी (उदाहरण का मामला खराब लिखित अनुक्रमण डेमन हो सकता है जो पढ़ने के साथ फाइल खोलता है। / झंडा लिखें जब इसे वास्तव में केवल पढ़ा जाना चाहिए)। inotifywaitनींद के बजाय अभी भी इस्तेमाल किया जा सकता है, बस स्लीप लाइन को बदल दें inotifywait -e close /path/to/file


धन्यवाद, मुझे इसकी जानकारी नहीं थी inotify। दुर्भाग्य से, यह मेरे बॉक्स पर स्थापित नहीं है, लेकिन मुझे यकीन है कि मुझे एक पैकेज मिलेगा। मेरे संपादन को इस कारण से देखें कि मुझे फ़ाइल को बंद करने की आवश्यकता क्यों है: यह एक डेटासेट है और इसे आगे संसाधित करने से पहले इसे पूरा करना होगा।
पीटर कोवाक

1
एक और पक्ष नोट: जबकि inotifywaitस्क्रिप्ट को "मतदान" से दो बार रोका जाएगा, ओपी को अभी भी lsofएक लूप में जांच करने की आवश्यकता है : यदि फ़ाइल दो बार खोली जाती है, तो एक बार बंद होने से inotifyघटना ट्रिगर हो सकती है , भले ही फ़ाइल बनने के लिए तैयार न हो हेरफेर (उदाहरण के लिए, कोड के अंतिम स्निपेट में, आपकी sleepकॉल को प्रतिस्थापित किया जा सकता है inotifywait)।
जॉन डब्ल्यूएच स्मिथ

@ जॉन close_writeको ठीक होना चाहिए क्योंकि एक समय में लिखने के लिए केवल एक ही प्रक्रिया हो सकती है। यह मान लेता है कि कोई दूसरा इसे बंद होने के बाद सीधे नहीं खोलेगा, लेकिन फिर वही मुद्दा lsofमतदान के साथ मौजूद है ।
ग्रीम

1
@Gememe जबकि यह ओपी के मामले में डिजाइन द्वारा सच हो सकता है, कर्नेल एक फाइल को लिखने के लिए दो बार खोलने की अनुमति देता है (जिस मामले में, CLOSE_WRITEदो बार ट्रिगर होता है)।
जॉन डब्ल्यूएच स्मिथ

@ जॉन, अपडेट किया गया।
ग्रीम

4

एक वैकल्पिक दृष्टिकोण के रूप में, यह एक पाइप के लिए एकदम सही मामला है - दूसरी प्रक्रिया पहली प्रक्रिया से आउटपुट प्राप्त करेगी जैसे ही यह उपलब्ध है, इसके बजाय पूरी प्रक्रिया समाप्त होने की प्रतीक्षा कर रही है:

process1 input_file.dat | process2 > output_file.dat

लाभ:

  • सामान्य रूप से बहुत तेज:
    • डिस्क से लिखना और पढ़ना नहीं है (यदि आप रैमडिस्क का उपयोग करते हैं तो इससे बचा जा सकता है)।
    • अधिक पूरी तरह से मशीन संसाधनों का उपयोग करना चाहिए।
  • परिष्करण के बाद हटाने के लिए कोई मध्यवर्ती फ़ाइल नहीं।
  • कोई जटिल लॉकिंग आवश्यक नहीं है, जैसा कि ओपी में है।

यदि आपके पास सीधे पाइप बनाने का कोई तरीका नहीं है, लेकिन आपके पास जीएनयू कोरुटिल्स हैं, तो आप इसका उपयोग कर सकते हैं:

tail -F -n +0 input_file.dat | process2 > output_file.dat

यह शुरू से इनपुट फ़ाइल पढ़ना शुरू कर देगा, भले ही फ़ाइल लिखने के माध्यम से पहली प्रक्रिया कितनी दूर हो (भले ही यह अभी तक शुरू नहीं हुई हो या पहले से ही समाप्त हो गई हो)।


हाँ, यह "स्पष्ट" समाधान होगा। दुर्भाग्य से, डेटा जनरेटिंग प्रक्रिया मेरे नियंत्रण से बाहर है (अन्य उपयोगकर्ता द्वारा संचालित)।
पीटर कोवाक

@PeterKovac यह अप्रासंगिक है: बिल्ली input_file.dat | process2 output_file.dat
MariusMatutiae

@MariusMatutiae लेकिन catऔर process2पहले खत्म कर सकता है process1समाप्त हो गया है। वे ब्लॉक नहीं करेंगे।
cpugeniusmv
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.