अनपेक्षित बैश निकास में बनाई गई अस्थायी फ़ाइलों को हटाना


89

मैं एक बैश स्क्रिप्ट से अस्थायी फाइलें बना रहा हूं। मैं उन्हें प्रसंस्करण के अंत में हटा रहा हूं, लेकिन चूंकि स्क्रिप्ट काफी लंबे समय से चल रही है, अगर मैं इसे मारता हूं या रन के दौरान बस CTRL-C करता है, तो अस्थायी फ़ाइलें हटाए नहीं जाते हैं।
क्या कोई तरीका है जिससे मैं उन घटनाओं को पकड़ सकता हूं और निष्पादन समाप्त होने से पहले फाइलों को साफ कर सकता हूं?

इसके अलावा, उन अस्थायी फ़ाइलों के नामकरण और स्थान के लिए किसी प्रकार का सबसे अच्छा अभ्यास है?
मैं वर्तमान में उपयोग करने के बीच निश्चित नहीं हूं:

TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...

तथा

TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...

या शायद कुछ बेहतर उपाय हैं?


जवाबों:


97

बाहर निकलने के लिए या नियंत्रण-सी पर सफाई करने के लिए आप " ट्रैप " सेट कर सकते हैं ।

trap "{ rm -f $LOCKFILE; }" EXIT

वैकल्पिक रूप से, मेरे पसंदीदा यूनिक्स-आइम्स में से एक फ़ाइल खोलना है, और फिर इसे तब हटाएं जब आपके पास अभी भी यह खुला हो। फ़ाइल फ़ाइल सिस्टम पर रहती है और आप इसे पढ़ और लिख सकते हैं, लेकिन जैसे ही आपका कार्यक्रम समाप्त होता है, फ़ाइल चली जाती है। यकीन नहीं है कि आप इसे कैसे कोस में करेंगे, हालांकि।

BTW: एक तर्क मैं आपके स्वयं के समाधान का उपयोग करने के बजाय mktemp के पक्ष में दूंगा: यदि उपयोगकर्ता का अनुमान है कि आपका प्रोग्राम विशाल अस्थायी फ़ाइलों को बनाने जा रहा है, तो वह TMPDIRकहीं और / set / var / tmp की तरह बड़ा सेट कर सकता है । mktemp पहचानता है कि, आपके हाथ से लुढ़का समाधान (दूसरा विकल्प) नहीं करता है। मैं अक्सर उपयोग करता हूं TMPDIR=/var/tmp gvim -d foo bar, उदाहरण के लिए।


8
बैश के साथ, exec 5<>$TMPFILEसंबंधों फ़ाइल वर्णनकर्ता 5 पढ़ने-लिखने के रूप में TMPFILE डॉलर हो गया है, और आप उपयोग कर सकते हैं <&5, >&5और /proc/$$/fd/5(लिनक्स) उसके बाद। एकमात्र समस्या यह है कि बैश में seekफंक्शन की कमी है ...
एपेमिएंट

आपके द्वारा दिए गए लिंक के बाद से आपने उत्तर दिया है कि मुझे जो सबसे अच्छा चाहिए उसकी व्याख्या करता है। धन्यवाद
skinp

4
नोटों की एक जोड़ी trap: फँसाने का कोई तरीका नहीं है SIGKILL(डिजाइन द्वारा, क्योंकि यह तुरंत निष्पादन को समाप्त कर देता है)। इसलिए, यदि ऐसा हो सकता है, तो एक फॉलबैक प्लान (जैसे tmpreaper) हो। दूसरे, जाल संचयी नहीं हैं - यदि आपके पास प्रदर्शन करने के लिए एक से अधिक कार्य हैं, तो वे सभी trapकमांड में होने चाहिए । एक से अधिक सफाई कार्यों का सामना करने का एक तरीका एक फ़ंक्शन को परिभाषित करना है (और आप इसे अपने कार्यक्रम के रूप में फिर से परिभाषित कर सकते हैं, यदि आवश्यक हो) और संदर्भ trap cleanup_function EXIT:।
टॉबी स्पाइट

1
मुझे उपयोग करना था trap "rm -f $LOCKFILE" EXITया मुझे फ़ाइल त्रुटि का अप्रत्याशित अंत मिलेगा।
जाको

3
शेलचेक ने एकल उद्धरणों का उपयोग करने के लिए चेतावनी दी, कि अभिव्यक्ति को 'अब' का विस्तार किया जाएगा जब जाल को लागू करने के बजाय बाद में दोहरे उद्धरण चिह्नों के साथ।
LaFayette

110

मैं आमतौर पर एक निर्देशिका बनाता हूं जिसमें मेरी सभी अस्थायी फ़ाइलों को रखना है, और उसके तुरंत बाद, स्क्रिप्ट से बाहर निकलने पर इस निर्देशिका को साफ करने के लिए एक EXIT हैंडलर बनाएं।

MYTMPDIR=$(mktemp -d)
trap "rm -rf $MYTMPDIR" EXIT

यदि आप अपनी सभी अस्थायी फ़ाइलों को नीचे रख देते हैं $MYTMPDIR, तो वे सभी हटा दिए जाएंगे जब आपकी स्क्रिप्ट अधिकांश परिस्थितियों में बाहर निकल जाएगी। SIGKILL (मार -9) के साथ एक प्रक्रिया को मारना इस प्रक्रिया को तुरंत ही मार देता है, इसलिए आपका EXIT हैंडलर उस स्थिति में नहीं चलेगा।


27
+1 निश्चित रूप से EXIT पर एक जाल का उपयोग करें, न कि मूर्खतापूर्ण TERM / INT / HUP / जो भी आप सोच सकते हैं उसके बारे में। हालांकि, के लिए याद बोली अपने पैरामीटर विस्तार और मैं होता भी आप की सिफारिश एकल उद्धरण अपने जाल: जाल 'rm- आरएफ "$ TMPDIR"' बाहर निकलें
lhunath

7
एकल उद्धरण, क्योंकि तब आपका जाल अभी भी काम करेगा यदि बाद में आपकी स्क्रिप्ट में आप circomstances के कारण TMPDIR को साफ करने और बदलने का निर्णय लेते हैं।
२०:०२ पर लुननाथ

1
@AaronDigulla $ () बनाम बैकटिक्स क्यों महत्वपूर्ण है?
ओगरे Psalm33


3
@AlexanderTorstling कोड को इंजेक्शन को रोकने के लिए हमेशा एकल-उद्धृत होना चाहिए जिसके परिणामस्वरूप मनमाना कोड निष्पादन होता है। यदि आप डेटा को एक बैश कोड STRING में विस्तारित करते हैं, तो वह डेटा अब कुछ भी कोड कर सकता है, जिसके परिणामस्वरूप निर्दोष कीड़े को सफ़ेद स्थान मिलता है, लेकिन विनाशकारी कीड़े जैसे कि विचित्र कारणों से अपने होमडायर को साफ़ करना या सुरक्षा छेद शुरू करना। ध्यान दें कि ट्रैप बैश कोड का एक स्ट्रिंग लेता है जिसका मूल्यांकन बाद में किया जाएगा। इसलिए बाद में जब जाल फँसता है, तो सिंगल कोट्स चले जाएंगे और सिर्फ सिंटैक्टिकल डबल कोट्स होंगे।
लुनानाथ

25

आप CTRL-C जैसी स्क्रिप्ट या सिग्नल से बाहर निकलने के लिए ट्रैप कमांड का उपयोग करना चाहते हैं । देखें ग्रेग के विकी जानकारी के लिए।

आपके टेंपइल के लिए, का उपयोग basename $0करना एक अच्छा विचार है, साथ ही एक टेम्प्लेट प्रदान करना जो पर्याप्त अस्थायी फ़ाइलों के लिए जगह प्रदान करता है:

tempfile() {
    tempprefix=$(basename "$0")
    mktemp /tmp/${tempprefix}.XXXXXX
}

TMP1=$(tempfile)
TMP2=$(tempfile)

trap 'rm -f $TMP1 $TMP2' EXIT

1
TERM / INT पर न फंसें। EXIT पर ट्रैप। प्राप्त संकेतों के आधार पर बाहर निकलने की स्थिति की भविष्यवाणी करने की कोशिश करना मूर्खतापूर्ण है और निश्चित रूप से एक प्रलाप नहीं है।
20 जून को लुननाथ

3
मामूली बिंदु: एकल बैकटिक्स के बजाय $ () का उपयोग करें। और $ 0 के आसपास दोहरे उद्धरण चिह्नों को रखें क्योंकि इसमें रिक्त स्थान हो सकते हैं।
आरोन दिगुल्ला

ठीक है, इस टिप्पणी में बैकटिक्स ठीक काम करता है, लेकिन यह एक उचित बिंदु है, इसका उपयोग करने की आदत में रहना अच्छा है $()। डबल कोट्स को भी जोड़ा।
ब्रायन कैंपबेल

1
आप सिर्फ TMP1 = $ (tempfile -s "XXXXXX") के साथ अपने पूरे सबरूटीन को बदल सकते हैं
रुस्लान कबालिन

4
@RuslanKabalin सभी सिस्टम में एक tempfileकमांड नहीं है, जबकि सभी उचित आधुनिक सिस्टम जिन्हें मैं जानता हूं कि एक mktempकमांड है।
ब्रायन कैंपबेल

9

बस ध्यान रखें कि उत्तर चुना हुआ है bashism, जिसका अर्थ है समाधान

trap "{ rm -f $LOCKFILE }" EXIT

केवल बैश में काम करेगा (यह Ctrl + c को नहीं पकड़ेगा यदि शेल dashया क्लासिक है sh), लेकिन यदि आप संगतता चाहते हैं, तो आपको अभी भी उन सभी संकेतों की गणना करने की आवश्यकता है जिन्हें आप फंसाना चाहते हैं।

यह भी ध्यान रखें कि जब स्क्रिप्ट सिग्नल "0" के लिए जाल से बाहर निकलती है (उर्फ EXIT) हमेशा trapआदेश के दोहरे निष्पादन के परिणामस्वरूप किया जाता है ।

EXIT सिग्नल होने पर सभी सिग्नलों को एक लाइन में न रखने का कारण।

बेहतर स्क्रिप्ट को समझने के लिए निम्नलिखित स्क्रिप्ट को देखें जो बिना बदलाव के विभिन्न प्रणालियों में काम करेगी:

#!/bin/sh

on_exit() {
  echo 'Cleaning up...(remove tmp files, etc)'
}

on_preExit() {
  echo
  echo 'Exiting...' # Runs just before actual exit,
                    # shell will execute EXIT(0) after finishing this function
                    # that we hook also in on_exit function
  exit 2
}


trap on_exit EXIT                           # EXIT = 0
trap on_preExit HUP INT QUIT TERM STOP PWR  # 1 2 3 15 30


sleep 3 # some actual code...

exit 

यह समाधान आपको अधिक नियंत्रण देगा क्योंकि आप अपने कुछ कोड को वास्तविक सिग्नल की घटना पर अंतिम निकास ( preExitफ़ंक्शन) से ठीक पहले चला सकते हैं और यदि आवश्यक हो तो आप वास्तविक EXIT सिग्नल (निकास के अंतिम चरण) पर कुछ कोड चला सकते हैं


4

$$ के साथ एक पूर्वानुमानित फ़ाइल नाम का उपयोग करने का विकल्प एक गैपिंग सुरक्षा छेद है और आपको कभी भी, कभी भी, इसका उपयोग करने के बारे में नहीं सोचना चाहिए। भले ही यह आपके एकल उपयोगकर्ता पीसी पर सिर्फ एक साधारण व्यक्तिगत स्क्रिप्ट हो। यह एक बहुत बुरी आदत है जिसे आपको प्राप्त नहीं करना चाहिए। BugTraq "असुरक्षित अस्थायी फ़ाइल" घटनाओं से भरा है। अस्थायी फ़ाइलों के सुरक्षा पहलू पर अधिक जानकारी के लिए यहां , यहां और यहां देखें ।

मैं शुरू में असुरक्षित TMP1 और TMP2 असाइनमेंट को उद्धृत करने के बारे में सोच रहा था, लेकिन दूसरे विचार पर यह एक अच्छा विचार नहीं होगा


मैं दे सकता हूँ अगर मैं कर सकता: सुरक्षा सलाह के लिए +1 और बुरा विचार और संदर्भ को उद्धृत न करने के लिए एक और +1
TMG

1

मैं उपयोग करना पसंद tempfileकरता हूं जो सुरक्षित तरीके से / tmp में एक फ़ाइल बनाता है और आपको इसके नामकरण के बारे में चिंता करने की आवश्यकता नहीं है:

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit

टेम्परेरी दुखद रूप से हालांकि बहुत सुरक्षित है, इसलिए इसे टालना बेहतर है या कम से कम इसका अनुकरण करें।
lericson

1

मैं विश्वास नहीं कर सकता कि इतने सारे लोग यह मानते हैं कि एक फ़ाइल नाम में कोई स्थान नहीं होगा। यदि $ TMPDIR को कभी भी "अस्थायी निर्देशिका" को सौंपा गया तो दुनिया दुर्घटनाग्रस्त हो जाएगी।

zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps")
trap "rm -f ${zTemp@Q}" EXIT

रिक्त स्थान और अन्य विशेष वर्ण जैसे सिंगल कोट्स और कैरिज रिटर्न फाइल नामों में कोड को सभ्य प्रोग्रामिंग की आदत की आवश्यकता के रूप में माना जाना चाहिए।


+1 जबकि एकल-उद्धरण trap 'rm -f "${zTemp}"' EXITसही ढंग से रिक्त स्थान और अन्य विशेष वर्णों को संभालता है, इस उत्तर का समाधान मूल्यांकन का बचाव नहीं करता है zTemp। इसलिए zTempस्क्रिप्ट में बाद में परिवर्तित होने के मूल्य के बारे में चिंता करने की कोई आवश्यकता नहीं है । इसके अलावा, zTempएक समारोह के लिए स्थानीय घोषित किया जा सकता है; यह एक वैश्विक स्क्रिप्ट चर होने की जरूरत नहीं है।
रॉबिन ए। मीडे

असाइनमेंट के आरएचएस के आसपास दोहरे-उद्धरण अनावश्यक हैं।
रॉबिन ए। मीडे

यह ध्यान दिया जाना चाहिए कि ${parameter@operator}विस्तार को बैश 4.4 (सितंबर 2016 में जारी) में जोड़ा गया था।
रॉबिन ए। मीडे

-4

आपको mktemp के साथ बनाई गई उन tmp फ़ाइलों को हटाने से परेशान होने की आवश्यकता नहीं है। बाद में उन्हें हटा दिया जाएगा।

यदि आप कर सकते हैं तो mktemp का उपयोग करें क्योंकि यह अधिक अनूठी फाइलें उत्पन्न करता है तो '$ $' उपसर्ग। और यह अस्थायी फ़ाइलों को बनाने के लिए और अधिक क्रॉस प्लेटफ़ॉर्म की तरह दिखता है, फिर उन्हें स्पष्ट रूप से / tmp में डाल दिया जाता है।


4
किसके द्वारा नष्ट किया गया या क्या?
इन्नाम

ऑपरेशन से हटा दिया गया। कुछ समय की अवधि के बाद ही फाइल सिस्टम
Mykola Golubyev

4
जादू? एक क्रोनजोब? या एक रिबूट सोलारिस मशीन?
इन्नाएम

शायद उनमें से एक है। यदि किसी रुकावट से अस्थायी फ़ाइल को नहीं हटाया गया था (तो यह बहुत बार नहीं होगा) किसी दिन tmp फाइलें निकाली जाएंगी - इसीलिए वे अस्थायी हो गईं।
मायकोला गोलुब्येव

21
आप नहीं कर सकते हैं, नहीं होना चाहिए, यह नहीं मान लेना चाहिए कि कुछ भी / tmp में हमेशा के लिए रहेगा; उसी समय, आपको यह नहीं मानना ​​चाहिए कि यह जादुई रूप से चला जाएगा।
इन्नाम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.