शेल स्क्रिप्ट में एक अस्थायी फ़ाइल कैसे बनाएं?


155

स्क्रिप्ट चलाते समय, मैं /tmpनिर्देशिका में एक अस्थायी फ़ाइल बनाना चाहता हूं ।

उस स्क्रिप्ट के निष्पादन के बाद, उस स्क्रिप्ट को साफ कर दिया जाएगा।

शेल स्क्रिप्ट में ऐसा कैसे करें?

जवाबों:


198
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
: ...
rm "$tmpfile"

आप यह सुनिश्चित कर सकते हैं कि जब स्क्रिप्ट से बाहर निकलता है (फाइल को मारता है और क्रैश करता है) तो फाइल डिस्क्रिप्टर को फाइल से हटाकर उसे हटा दिया जाता है। /proc/$PID/fd/$FDजब तक फाइल डिस्क्रिप्टर खुला रहता है, तब तक फाइल उपलब्ध रहती है (स्क्रिप्ट के लिए; अन्य प्रक्रियाओं के लिए नहीं, बल्कि काम के इर्द-गिर्द)। जब यह बंद हो जाता है (जो प्रक्रिया समाप्त होने पर कर्नेल स्वचालित रूप से करता है) फ़ाइल सिस्टम फ़ाइल को हटा देता है।

tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3

4
अच्छा जवाब, दुर्घटना के मामले में फाइल डिस्क्रिप्टर के साथ सुरुचिपूर्ण समाधान +1
अराजकता

2
/proc- सिवाय उन प्रणालियों को छोड़कर जिनके पास यह नहीं है।
डेनिस विलियमसन

4
क्या करता exec 3> "$tmpfile"है? क्या यह केवल उपयोगी नहीं है अगर tmpfile एक स्टैंड-अलोन स्क्रिप्ट है?
अलेक्सज मगुरा

5
आप बनी हुई FD से कैसे पढ़ते हैं?
Eckes

3
"आप बिल्ली <3 या कुछ इसी तरह का उपयोग कर सकते हैं।" वास्तव में जो 3 @ dragon788 नामक फ़ाइल से पढ़ता है। साथ ही, cat <&3देंगे Bad file descriptor। अगर आप इसे ठीक करते हैं या इसे हटाते हैं तो मैं इसकी सराहना करूंगा; गलत सूचना ज्यादा मदद नहीं करती है।
डैनियल फैरेल

65

mktempएक अस्थायी फ़ाइल या निर्देशिका बनाने के लिए उपयोग करें :

temp_file=$(mktemp)

या एक डाइरकोट्री के लिए:

temp_dir=$(mktemp -d)

स्क्रिप्ट के अंत में आपको अस्थायी फ़ाइल को हटाना होगा:

rm ${temp_file}
rm -R ${temp_dir}

mktemp /tmpनिर्देशिका में या --tmpdirतर्क के साथ दिए गए डॉक्यूमेंटरी में फ़ाइल बनाता है।


20
आप trap "rm -f $temp_file" 0 2 3 15फ़ाइल बनाने के बाद सही उपयोग कर सकते हैं ताकि जब स्क्रिप्ट बाहर निकल जाए या ctrl-Cफ़ाइल के साथ रोका जाए तब भी हटा दिया जाए।
०27:२

1
@ हर्टेल क्या होता है अगर EXITकेवल हुक के लिए है trap?
हौके लैजिंग

4
@HaLLaging अगर स्क्रिप्ट को Ctrl + C के साथ रोका जाता है तो जाल में आग नहीं लगती है। ध्यान देने वाली बात यह है कि TRAP आपकी मदद नहीं करता है kill -9 $somepid। वह विशेष रूप से मार संकेत इंस्टा-मौत है और कुछ नहीं हो रहा है।
ड्रैगन 788

5
@ dragon788 क्या आपने कोशिश की है? तुम्हे करना चाहिए। bash -c 'echo $$; trap "echo foo" 0; sleep 5'
Hauke ​​Laging

फँसाना EXITकाफी है।
Kusalananda

15

यदि आप सिस्टम पर हैं, जिसमें mktemp है , तो आपको इसे अन्य उत्तरों के रूप में उपयोग करना चाहिए।

POSIX उपकरण के साथ:

umask 0177
tmpfile=/tmp/"$0"."$$"."$(awk 'BEGIN {srand();printf "%d\n", rand() * 10^10}')"
trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
: > "$tmpfile"

यदि EXITकेवल हुक के लिए क्या होता है trap?
हॉके लैजिंग

@HaLLaging: tmpfileस्क्रिप्ट से बाहर निकलने से पहले ही हटा दिया जाना चाहिए, लेकिन तब नहीं जब स्क्रिप्ट को अन्य सिग्नल मिले।
cuonglm

यहाँ ऐसा नहीं है (GNU बैश, संस्करण 4.2.53)।
हॉके लैजिंग

@ हॉकिंग: आपका क्या मतलब है That's not what happens?
cuonglm

3
mktempएक अलग सिंटैक्स के साथ एचपी / यूएक्स में उत्पन्न हुआ। टॉड सी। मिलर ने 90 के दशक के मध्य में (FreeBSD और NetBSD द्वारा प्रतिलिपि) OpenBSD के लिए एक अलग बनाया और बाद में इसे स्टैंडअलोन उपयोगिता (www.mktemp.org) के रूप में भी उपलब्ध कराया। यह वह है जो आमतौर पर लिनक्स पर उपयोग किया जाता था जब तक कि (ज्यादातर संगत) mktempउपयोगिता को 2007 में जीएनयू कोर्यूटिल्स में जोड़ा गया था। बस कहने के लिए एक वास्तव में mktempजीएनयू उपयोगिता नहीं कह सकता है।
स्टीफन चेज़लस

14

कुछ गोले में अंतर्निहित सुविधा है।

zsh

zshकी =(...)प्रक्रिया प्रतिस्थापन के रूप में एक अस्थायी फ़ाइल का उपयोग करता है। उदाहरण के लिए =(echo test)एक अस्थायी फ़ाइल के पथ में विस्तार होता है, जिसमें सम्‍मिलित है test\n

$ {cat $file; ls -l /dev/fd/3; echo test2 >&3; cat $file} 3<> ${file::==(echo test)}
test
lrwx------ 1 stephane stephane 64 Jan 30 11:19 /dev/fd/3 -> /tmp/zshMLbER0
test2

एक बार कमांड समाप्त होने के बाद वह फाइल अपने आप हट जाती है।

लिनक्स पर bash / zsh।

यहाँ-फ़ाइलें या यहाँ-में तार bashऔर zshहटाए गए अस्थायी फ़ाइलों के रूप में कार्यान्वित किए जाते हैं।

तो अगर तुम करते हो:

exec 3<<< test

फ़ाइल डिस्क्रिप्टर 3 एक हटाई गई अस्थायी फ़ाइल से जुड़ा है test\n

आप इसके साथ इसकी सामग्री प्राप्त कर सकते हैं:

cat <&3

यदि लिनक्स पर है, तो आप उस फ़ाइल को पढ़ या लिख ​​भी सकते हैं /dev/fd/3

$ exec 3<<< test
$ cat <&3
test
$ echo foo > /dev/fd/3
$ cat /dev/fd/3
foo

(कुछ अन्य गोले पाइप का उपयोग करते हैं, या उपयोग कर सकते हैं /dev/nullयदि यहाँ डॉक्टर खाली है)।

POSIX

कोई mktempPOSIX उपयोगिता नहीं है। POSIX हालांकि एक mkstemp(template)C API को निर्दिष्ट करता है , और m4मानक उपयोगिता mkstemp()उसी नाम से m4 फ़ंक्शन के साथ उस API को उजागर करती है ।

mkstemp()आपको एक यादृच्छिक नाम के साथ एक फ़ाइल नाम देता है जिसे उस समय कहा जाता था जब फ़ंक्शन को कॉल नहीं किया जाता था। यह फ़ाइल को रेस-फ्री तरीके से 0600 अनुमतियों के साथ बनाता है।

तो, आप कर सकते हैं:

tmpfile=$(
  echo 'mkstemp(template)' |
    m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit

ध्यान दें कि बाहर निकलने पर आपको क्लीन-अप को संभालने की आवश्यकता होती है, हालाँकि यदि आपको फ़ाइल को एक निश्चित संख्या में लिखने और पढ़ने की आवश्यकता है, तो आप इसे यहाँ-डॉक्स / यहाँ की तरह बनाने के बाद इसे खोल सकते हैं और हटा सकते हैं- ऊपर स्ट्रिंग दृष्टिकोण:

tmpfile=$(
  echo 'mkstemp(template)' |
    m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit

# open once for writing, twice for reading:
exec 3> "$tempfile" 4< "$tempfile" 5< "$tempfile"

rm -f -- "$tmpfile"

cmd >&3   # store something in the temp file
exec 3>&- # fd no longer needed

# read the content twice:
cat <&4
cat <&5

आप एक बार पढ़ने के लिए फ़ाइल खोल सकते हैं, और दो रीड्स के बीच में रिवाइंड कर सकते हैं, हालाँकि ऐसी कोई POSIX उपयोगिता नहीं है जो उस रिवाइंडिंग ( lseek()) को कर सके, इसलिए आप इसे POSIX स्क्रिप्ट ( zsh( sysseekबिल्टिन) और ksh93( <#((...))ऑपरेटर) में आंशिक रूप से नहीं कर सकते हैं हालांकि यह करो)।


1
बैश भी प्रक्रिया प्रतिस्थापन का उपयोग कर रहा है<()
WinnieNicklaus

3
@WinnieNicklaus, हाँ, लेकिन यह अस्थायी फ़ाइलों का उपयोग नहीं करता है इसलिए यहाँ अप्रासंगिक है। प्रक्रिया प्रतिस्थापन को ksh द्वारा प्रस्तुत किया गया था, जो कि bash और zsh द्वारा कॉपी किया गया था, और zsh ने इसे 3rd फॉर्म के साथ बढ़ाया =(...):।
स्टीफन चेज़लस

7

यहाँ Hauke ​​Laging की लाइन में थोड़ा सुधार हुआ जवाब है:

#!/bin/bash

tmpfile=$(mktemp)  # Create a temporal file in the default temporal folder of the system

# Lets do some magic for the tmpfile to be removed when this script ends, even if it crashes
exec {FD_W}>"$tmpfile"  # Create file descriptor for writing, using first number available
exec {FD_R}<"$tmpfile"  # Create file descriptor for reading, using first number available
rm "$tmpfile"  # Delete the file, but file descriptors keep available for this script

# Now it is possible to work with the temporal file
echo foo >&$FD_W
echo bar >&$FD_W  # Note that file descriptor always concatenates, not overwrites

cat <&$FD_R

2
यह ध्यान दिया जाना चाहिए कि सामग्री केवल एक बार उपलब्ध है। यानी अगर मैं दूसरी बार बिल्ली <और $ FD_R करता हूं, तो कोई आउटपुट नहीं होता है। Unix.stackexchange.com/questions/166482/… देखें । यदि प्रोग्राम क्रैश हो जाता है, तो क्या फ़ाइल को स्वचालित रूप से हटाने का कोई तरीका है, लेकिन यह कई बार सुलभ है?
स्माइली

0

आमतौर पर अस्थायी फ़ाइलों के साथ मेरा वर्कफ़्लो कुछ बैश स्क्रिप्ट के कारण होता है जिसका मैं परीक्षण कर रहा हूं। मैं teeइसे ऊपर ले जाना चाहता हूं ताकि मैं देख सकूं कि यह काम कर रहा है और मेरी प्रक्रिया के अगले पुनरावृत्ति के लिए आउटपुट को बचा सकता है। मैंने एक फाइल बनाई है जिसका नाम हैtmp

#!/bin/bash
echo $(mktemp /tmp/$(date +"%Y-%m-%d_%T_XXXXXX"))

ताकि मैं इसका उपयोग कर सकूं

$ some_command --with --lots --of --stuff | tee $(tmp)

यादृच्छिक मूल्यों से पहले प्रारूपित प्रारूप मुझे पसंद है इसका कारण यह है कि यह मुझे उस tmp फ़ाइल को खोजने की अनुमति देता है जिसे मैंने अभी आसानी से बनाया है, और मुझे यह सोचने की ज़रूरत नहीं है कि अगली बार इसका नाम क्या है (और सिर्फ अपनी खतरे की स्क्रिप्ट प्राप्त करने पर ध्यान केंद्रित करें काम करने के लिए)।

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