अस्थायी फ़ोल्डर जो स्वचालित रूप से प्रक्रिया से बाहर निकलने के बाद नष्ट हो जाता है


10

क्या हम अस्थायी फ़ोल्डर जैसे अस्थायी फ़ाइलों का उपयोग कर सकते हैं

TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP

cat <&3

जो इस शेल के बाहर निकलने के बाद अपने आप नष्ट हो जाएगा?


जवाबों:


12

एक अस्थायी फ़ाइल के मामले में, प्रश्न में आपका उदाहरण इसे बनाएगा, फिर निर्देशिका से इसे अनलिंक कर देगा (इसे "गायब" कर देगा), और जब स्क्रिप्ट दर्जकर्ता (संभवत: समाप्ति पर) बंद हो जाती है, तो फ़ाइल द्वारा लिया गया स्थान सिस्टम द्वारा पुनः प्राप्त किया जा सकेगा। C जैसी भाषाओं में अस्थायी फ़ाइलों से निपटने का यह एक सामान्य तरीका है।

यह है, जहां तक ​​मुझे पता है, एक निर्देशिका को उसी तरह से खोलना संभव नहीं है, कम से कम किसी भी तरह से ऐसा नहीं है जो निर्देशिका को सार्थक बना सके।

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

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT

# The rest of the script goes here.

या आप एक सफाई समारोह कह सकते हैं:

cleanup () {
    rm -f "$tmpfile"
    rm -rf "$tmpdir"
}

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap cleanup EXIT

# The rest of the script goes here.

EXITजाल प्राप्त होने पर निष्पादित नहीं किया जाएगा KILLसंकेत (जो ट्रैप नहीं किया जा सकता है), जिसका अर्थ है कि वहाँ हो जाएगा कोई सफाई तो प्रदर्शन किया। हालांकि यह निष्पादित करेंगे जब एक की वजह से समाप्त INTया TERMसंकेत (अगर साथ चल रहा bashया ksh, अन्य गोले में आप के बाद इन संकेतों को जोड़ सकते हैं EXITमें trapकमांड लाइन), या जब सामान्य रूप से कारण स्क्रिप्ट के अंत में आ रहा है या एक को क्रियान्वित करने के लिए बाहर निकलने exitकहते हैं।


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

1
@derobert और ऐसी अनलिंक की गई निर्देशिका में .और ..प्रविष्टियाँ भी नहीं हैं। (लिनक्स पर परीक्षण किया गया, मुझे नहीं पता कि क्या यह प्लेटफ़ॉर्म पर संगत है।)
कैस्पर


1
ध्यान दें कि अगर स्क्रिप्ट exec another-commandस्पष्ट रूप से कॉल करता है तो EXIT जाल को निष्पादित नहीं किया जाता है ।
स्टीफन चेजेलस


6

एक शेल-फंक्शन लिखें जिसे आपकी स्क्रिप्ट खत्म होने पर निष्पादित किया जाएगा। नीचे दिए गए उदाहरण में मैं इसे 'सफाई' कहता हूं और बाहर निकलने के स्तर पर निष्पादित होने के लिए एक जाल सेट करता हूं, जैसे: 0 1 2 3 3 6

trap cleanup 0 1 2 3 6

cleanup()
{
  [ -d $TMP ] && rm -rf $TMP
}

अधिक जानकारी के लिए इस पोस्ट को देखें ।


वे "बाहर निकलने के स्तर" नहीं हैं , लेकिन संकेत संख्याएं, और प्रश्न का उत्तर जो आप लिंक कर रहे हैं, बस यही बताते हैं। जाल cleanupएक स्वच्छ निकास (0) से पहले और SIGHUP (1), SIGINT (2), SIGQUIT (3) और SIGABRT (6) प्राप्त करने पर चलेगा। यह तब नहीं चलेगा cleanupजब स्क्रिप्ट SIGTERM, SIGSEGV, SIGKILL, SIGPIPE आदि के कारण बाहर निकल जाए, यह स्पष्ट रूप से कमी है।
मॉवी

6

आप इसमें chdir कर सकते हैं और फिर इसे हटा सकते हैं, बशर्ते कि आप इसके अंदर के रास्तों का उपयोग करने की कोशिश न करें:

#! /bin/sh
dir=`mktemp -d`
cd "$dir"
exec 4>file 3<file
rm -fr "$dir"

echo yes >&4    # OK
cat <&3         # OK

cat file        # FAIL
echo yes > file # FAIL

मैंने जाँच नहीं की है, लेकिन यह शायद एक ही समस्या है जब सी में ओपनैट (2) का उपयोग एक निर्देशिका के साथ किया जाता है जो अब फ़ाइल सिस्टम में मौजूद नहीं है।

यदि आप रूट पर हैं और लिनक्स पर हैं, तो आप एक अलग नामस्थान और उसके mount -t tmpfs tmpfs /dirअंदर खेल सकते हैं ।

यदि आपकी स्क्रिप्ट एक अशुद्ध निकास (जैसे SIGKILL के साथ) में मजबूर हो तो विहित उत्तर (EXIT पर एक जाल सेट) काम नहीं करते हैं; जो संवेदनशील डेटा को चारों ओर लटका हुआ छोड़ सकता है।

अपडेट करें:

यहाँ एक छोटी सी उपयोगिता है जो नेमस्पेस दृष्टिकोण को लागू करती है। इसके साथ संकलित किया जाना चाहिए

cc -Wall -Os -s chtmp.c -o chtmp

और दी गई CAP_SYS_ADMINफ़ाइल क्षमताओं (रूट के रूप में) के साथ

setcap CAP_SYS_ADMIN+ep chtmp

जब (एक सामान्य) उपयोगकर्ता के रूप में चलाते हैं

./chtmp command args ...

यह अपने फाइल सिस्टम नेमस्पेस को अनशेयर करेगा, इसमें एक tmpfs फाइल सिस्टम माउंट करेगा /proc/sysvipc, इस पर chdir और commandदिए गए तर्कों के साथ चल सकता है। क्षमताओं को विरासत में नहींcommand मिलेगा ।CAP_SYS_ADMIN

वह फाइलसिस्टम किसी अन्य प्रक्रिया से सुलभ नहीं होगा जहां से शुरू नहीं हुआ है command, और यह जादुई रूप से गायब हो जाएगा (सभी फाइलों के साथ जो इसके अंदर बनाई गई थीं) जब commandऔर उसके बच्चों की मृत्यु हो जाती है, तो कोई फर्क नहीं पड़ता कि ऐसा कैसे होता है। ध्यान दें कि यह केवल माउंट नेमस्पेस को अनचेक कर रहा है - commandएक ही उपयोगकर्ता द्वारा संचालित और अन्य प्रक्रियाओं के बीच कोई कठिन बाधाएं नहीं हैं ; वे अभी भी या तो के माध्यम से अपने नाम स्थान के अंदर चुपके सकता है ptrace(2), /proc/PID/cwdया अन्य तरीकों से।

"बेकार" /proc/sysvipcका अपहरण निश्चित रूप से मूर्खतापूर्ण है, लेकिन विकल्प /tmpखाली निर्देशिकाओं के साथ स्पैम के लिए होता है जिन्हें हटाया जाना चाहिए या कांटे और इंतजार के साथ इस छोटे से कार्यक्रम को जटिल करना होगा। वैकल्पिक रूप से, dirउदाहरण के लिए बदला जा सकता है। /mnt/chtmpऔर इसे स्थापना पर मूल द्वारा बनाया गया है; इसे उपयोगकर्ता-कॉन्फ़िगर करने योग्य न बनाएं और इसे उपयोगकर्ता के स्वामित्व वाले पथ पर सेट न करें क्योंकि यह आपको सहानुभूति जाल और अन्य बालों वाले सामान पर खर्च करने के लिए उजागर कर सकता है।

chtmp.c

#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mount.h>
int main(int argc, char **argv){
        char *dir = "/proc/sysvipc";    /* LOL */
        if(argc < 2 || !argv[1]) errx(1, "usage: %s prog args ...", *argv);
        argv++;
        if(unshare(CLONE_NEWNS)) err(1, "unshare(CLONE_NEWNS)");
        /* "modern" systemd remounts all mount points MS_SHARED
           see the NOTES in mount_namespaces(7); YUCK */
        if(mount("none", "/", 0, MS_REC|MS_PRIVATE, 0))
                err(1, "mount(/, MS_REC|MS_PRIVATE)");
        if(mount("tmpfs", dir, "tmpfs", 0, 0)) err(1, "mount(tmpfs, %s)", dir);
        if(chdir(dir)) err(1, "chdir %s", dir);
        execvp(*argv, argv);
        err(1, "execvp %s", *argv);
}

1
यहां तक ​​कि अगर आप जड़ नहीं हैं, तो आप एक नया उपयोगकर्ता नाम स्थान बनाकर और उसके अंदर tmpfs माउंट करके नामस्थान के साथ कर सकते हैं। बाहर की दुनिया के लिए नए डायर के लिए तस्करी थोड़ी मुश्किल है, लेकिन यह संभव होना चाहिए।
आर .. गिटहब स्टॉप हेल्पिंग ICE

इसके लिए अभी भी CAP_SYS_ADMIN की आवश्यकता है। मेरे पास एक छोटी सी सेट-सक्षम उपयोगिता का विचार है जो ऐसा करेगा, मैं इसके साथ उत्तर को अपडेट करूंगा।
qubert

1
जब तक कर्नेल को बंद करने के लिए बंद नहीं किया जाता है, तब तक उपयोगकर्ता नामस्थानों का निर्माण एक विशेषाधिकार प्राप्त ऑपरेशन नहीं है। अंतर्निहित डिज़ाइन ऐसा है कि आम उपयोगकर्ताओं को बिना किसी विशेष क्षमता के अनुमति देने के लिए सुरक्षित होना चाहिए। हालांकि, पर्याप्त हमले की सतह / जोखिम है जो कई डिस्ट्रोस इसे अक्षम करते हैं, मुझे लगता है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

मैंने टर्मिनल में कोशिश की। कुछ अस्थायी डायर, rm $PWDकाम में, शेल उस डायर में अभी भी है। लेकिन कोई भी नई फाइल इस "फ़ोल्डर" में नहीं डाली जा सकती है। केवल आप ऐसा कर सकते हैं / फ़ाइल और 3, और 4 के साथ पढ़ा / लिखा जा सकता है। तो यह अभी भी "अस्थायी फ़ाइल" है, न कि "अस्थायी फ़ोल्डर"।
बॉब जॉनसन

@ याकूब जॉनसन मेरे जवाब में जो मैं पहले से ही कह रहा था, उससे अलग नहीं है ;-)
qubert

0

क्या आपको एक विशिष्ट शेल की आवश्यकता है?

यदि zsh एक विकल्प है, तो कृपया पढ़ें zshexpn(1):

यदि <(...) के बजाय = (...) का उपयोग किया जाता है, तो एक तर्क के रूप में पारित फाइल सूची प्रक्रिया के आउटपुट वाले एक अस्थायी फ़ाइल का नाम होगा। इनपुट फ़ाइल पर lseek(देखें lseek(2)) की अपेक्षा करने वाले प्रोग्राम के लिए इसका उपयोग <फॉर्म के बजाय किया जा सकता है ।

[...]

एक अन्य समस्या किसी भी समय है कि एक अस्थायी फ़ाइल की आवश्यकता है एक प्रतिस्थापन के साथ एक नौकरी खोल द्वारा अस्वीकृत किया जाता है इस मामले में जहां भी शामिल है, उठता है &!या &|एक आदेश एक प्रतिस्थापन युक्त के अंत में दिखाई देता है। उस मामले में अस्थायी फ़ाइल को साफ नहीं किया जाएगा क्योंकि शेल में अब नौकरी की कोई स्मृति नहीं है। एक वर्कअराउंड का उपयोग करने के लिए एक उपधारा, उदाहरण के लिए,

(mycmd =(myoutput)) &!

के रूप में forked उपधारा समाप्त होने के लिए प्रतीक्षा करेगा, तो अस्थायी फ़ाइल को हटा दें।

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

() {
   print File $1:
   cat $1
} =(print This be the verse)

निम्नलिखित के समान कुछ आउटपुट

File /tmp/zsh6nU0kS:
This be the verse

उदाहरण के लिए मैं एक फाइल को डिक्रिप्ट करने के लिए राइफल (रेंजर फाइल मैनेजर का हिस्सा) में इसका उपयोग करता हूं और फिर अस्थायी फाइल पर राइफल चलाता हूं, जो उपप्रकार समाप्त होने पर हटा दी जाती है। (सेट करना न भूलें $TERMCMD)

# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.