हार्डलिंक के साथ सीपी के व्यवहार से आश्चर्यचकित


20

मैं हार्डलिंक्स की धारणा को अच्छी तरह से समझता हूं, और cp--- और यहां तक ​​कि हाल ही में POSIX चश्मा --- जैसे कई बार बुनियादी उपकरणों के लिए मैन पेज पढ़ चुका हूं । फिर भी मैं निम्नलिखित व्यवहार का पालन करने के लिए आश्चर्यचकित था:

$ echo john > john
$ cp -l john paul
$ echo george > george

इस बिंदु पर johnऔर paulएक ही इनोड (और सामग्री) georgeहोगा , और दोनों मामलों में अलग-अलग होगा। अब हम करते हैं:

$ cp george paul

इस बिंदु पर मुझे उम्मीद थी georgeऔर paulअलग-अलग इनोड संख्याएं थीं लेकिन एक ही सामग्री --- यह अपेक्षा पूरी हो गई थी --- लेकिन मुझे यह भी उम्मीद थी paulकि अब से एक अलग इनोड संख्या है john, और johnअभी भी सामग्री है john। यह वह जगह है जहां मैं हैरान था। यह पता चलता है कि गंतव्य पथ पर किसी फ़ाइल की प्रतिलिपि बनाने paulसे अन्य सभी गंतव्य पथों पर उसी फ़ाइल (समान इनोड) को स्थापित करने का परिणाम होता है, जो इनोड को साझा paulकरता है। मैं सोच रहा था कि cpएक नई फ़ाइल बनाता है और इसे पुरानी फ़ाइल के कब्जे वाले स्थान पर ले जाता है paul। इसके बजाय ऐसा लगता है कि मौजूदा फ़ाइल को खोलना है paul, उसे छोटा करना है, और लिखना हैgeorgeउस मौजूदा फ़ाइल में सामग्री। इसलिए एक ही "इनोड" वाली किसी भी अन्य "फाइल" को उसी समय अपडेट किया जाता है।

ठीक है, यह एक व्यवस्थित व्यवहार है और अब जब मैं यह उम्मीद करना जानता हूं कि मैं यह पता लगा सकता हूं कि इसके आसपास कैसे काम किया जाए, या उचित तरीके से इसका लाभ उठाएं। मुझे ऐसी कौन सी पहेलियाँ हैं जहाँ मुझे इस व्यवहार को देखना चाहिए था? मुझे आश्चर्य होगा कि अगर यह दस्तावेजों में कहीं दस्तावेज नहीं है तो मैंने पहले ही देख लिया है। लेकिन जाहिरा तौर पर मैं इसे याद किया, और अब एक स्रोत नहीं मिल सकता है जो इस व्यवहार पर चर्चा करता है।

जवाबों:


4

पहला, यह इस तरह से क्यों किया जाता है? एक कारण ऐतिहासिक है: यह है कि यह यूनिक्स फर्स्ट एडिशन में कैसे किया गया था ।

फाइलें जोड़े में ली जाती हैं; पहला पढ़ने के लिए खोला जाता है, दूसरा बनाया गया मोड 17. फिर पहले को दूसरे में कॉपी किया जाता है।

"बनाया गया" creatसिस्टम कॉल को संदर्भित करता है (वह जो प्रसिद्ध ई याद कर रहा है ), जो मौजूदा फ़ाइल को दिए गए नाम से काटता है यदि कोई है।

और यहाँcp यूनिक्स सेकेंड एडिशन का सोर्स कोड है (मैं फर्स्ट एडिशन का सोर्स कोड नहीं ढूँढ सकता)। आप openस्रोत फ़ाइल के creatलिए और दूसरी फ़ाइल के लिए कॉल देख सकते हैं ; और, पहले संस्करण में सुधार के रूप में, यदि दूसरी फ़ाइल एक मौजूदा निर्देशिका है, तो cpउस निर्देशिका में एक फ़ाइल बनाता है।

लेकिन, आप पूछ सकते हैं कि उस समय ऐसा क्यों किया गया था? "यूनिक्स ने मूल रूप से ऐसा क्यों किया था" का जवाब लगभग हमेशा सादगी है। cpपढ़ने के लिए अपना स्रोत खोलता है और अपनी मंजिल बनाता है - और फ़ाइल बनाने के लिए सिस्टम कॉल एक मौजूदा फ़ाइल को लिखने के लिए खोलकर उसे अधिलेखित कर देता है, क्योंकि इससे कॉल करने वाले को दिए गए नाम से किसी फ़ाइल की सामग्री को लागू करने की अनुमति मिलती है या नहीं फ़ाइल पहले से मौजूद है या नहीं।

अब, जहाँ यह प्रलेखित है: FreeBSD मैन पेज में

प्रत्येक गंतव्य फ़ाइल जो पहले से मौजूद है, यदि अनुमतियाँ अनुमति देती हैं, तो इसकी सामग्री ओवरराइट हो जाती है। इसका मोड, यूजर आईडी, और ग्रुप आईडी अपरिवर्तित है जब तक -p विकल्प निर्दिष्ट नहीं किया गया था।

यह शब्द कम से कम 1990 तक वापस मौजूद था (जब बीएसडी 4.3BSD था)। सोलारिस 10 पर इसी तरह के शब्द हैं :

यदि target_file मौजूद है, तो cp अपनी सामग्री को अधिलेखित कर देता है, लेकिन मोड (और ACL यदि लागू हो), स्वामी, और इसके साथ जुड़े समूह परिवर्तित नहीं होते हैं।

आपका मामला HP-UX 10 मैनुअल में भी लिखा गया है :

यदि new_file अन्य लिंक वाली मौजूदा फ़ाइल का लिंक है, तो मौजूदा फ़ाइल को ओवरराइट करता है और सभी लिंक को बरकरार रखता है।

POSIX इसे मानक रूप में रखता है। एकल यूनिक्स v2 से उद्धरण :

यदि dest_file मौजूद है, तो निम्न चरण उठाए गए हैं: (…) dest_file के लिए एक फ़ाइल विवरणक XSH विनिर्देशन ओपन () फ़ंक्शन के बराबर क्रिया करके प्राप्त किया जाएगा, जिसे dest_file को पथ तर्क के रूप में उपयोग किया जाता है, और बिट_ समावेशी या O_WRONLY और O_TRUNC का समावेश है टॉलग तर्क के रूप में।

मैन पेज और विनिर्देश जो मैंने उद्धृत किया है, यह निर्दिष्ट करता है कि यदि -fविकल्प पारित हो गया है और लक्ष्य फ़ाइल को खोलने / बनाने का प्रयास विफल रहता है (आमतौर पर फ़ाइल लिखने की अनुमति नहीं होने के कारण), cpलक्ष्य को हटाने और फिर से फ़ाइल बनाने का प्रयास करता है। । यह आपके परिदृश्य में कड़ी कड़ी को तोड़ देगा।

आप GNU कोरुटिल्स मैनुअल के खिलाफ एक दस्तावेज बग की रिपोर्ट करना चाह सकते हैं , क्योंकि यह इस व्यवहार को दस्तावेज नहीं करता है। यहां तक ​​कि इसका वर्णन --preserve=links, जो आपके परिदृश्य में paulलिंक को हटा दिया जाएगा और एक नई फ़ाइल बनाई जा रही है, यह स्पष्ट नहीं करता है कि इसके बिना क्या होता है --preserve=links। इसके -fबिना क्या होता है इसके प्रकार का वर्णन है, लेकिन इसे वर्तनी नहीं दी गई है ("जब इस विकल्प के बिना प्रतिलिपि और लेखन के लिए कोई मौजूदा गंतव्य फ़ाइल नहीं खोली जा सकती है, तो प्रतिलिपि विफल हो जाती है। हालांकि, --फोर्स,…" के साथ)।


आप ऐसा क्यों कहते हैं "क्योंकि इससे कॉल करने वाले को फ़ाइल नाम का स्वामित्व लेने की अनुमति मिलती है या नहीं फ़ाइल पहले से मौजूद है या नहीं"? Cp पहले से मौजूद फ़ाइल का स्वामित्व नहीं लेता है।
jrw32982

@ jrw32982 का मतलब था कि फ़ाइल में क्या जाता है, यह निर्णय लेने के अर्थ में स्वामित्व है, फ़ाइल मेटाडेटा के अर्थ में स्वामित्व नहीं है। मैंने उस वाक्य को फिर से लिखा है।
गिल्स एसओ- बुराई को रोकना '

20

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

यह भी ध्यान दें कि यदि cpपहले से मौजूद डेस्टिनेशन फाइल को "रिप्लेस" करना है, तो उचित है कि इसे आश्चर्यजनक या गलत माना जा सकता है, शायद "राइटिंग" की तुलना में। उदाहरण के लिए:

  • यदि cpपहले पुरानी फाइल को डिलीट किया है और फिर एक नया बनाया है, तो उस समय का अंतराल होगा, जिसके दौरान फाइल अनुपस्थित होगी, जो आश्चर्य की बात होगी।
  • यदि cpपहले एक अस्थायी फ़ाइल बनाई गई थी और फिर इसे स्थानांतरित कर दिया गया था, तो शायद यह इस बात का दस्तावेज होना चाहिए, इस तथ्य के कारण कि अजीब नामों वाली ऐसी अस्थायी फ़ाइलों को कभी-कभार ही देखा जाएगा ... लेकिन ऐसा नहीं है।
  • यदि cpअनुमतियों के कारण पुरानी फ़ाइल के समान निर्देशिका में एक नई फ़ाइल नहीं बनाई जा सकती है, तो यह दुर्भाग्यपूर्ण होगा (विशेषकर यदि यह पहले ही पुरानी हटा दी गई हो)।
  • यदि फ़ाइल को चलाने वाले उपयोगकर्ता के स्वामित्व में नहीं था cpऔर चलने वाला उपयोगकर्ता cpनहीं था, rootतो नई फ़ाइल के स्वामी और अनुमतियों का मिलान नई फ़ाइल से करना असंभव होगा।
  • यदि फ़ाइल में फैंसी विशेष विशेषताएं हैं, जिनके cpबारे में नहीं पता है, तो ये कॉपी में खो जाएंगे। आजकल cpविस्तारित विशेषताओं जैसी चीजों को मज़बूती से समझने के लिए कार्यान्वयन की आवश्यकता होती है , लेकिन यह हमेशा ऐसा नहीं था। और अन्य चीजें हैं, जैसे कि MacOS संसाधन कांटे, या, दूरस्थ फाइल सिस्टम के लिए, मूल रूप से कुछ भी।

तो निष्कर्ष में: अब आप जानते हैं कि cpवास्तव में क्या होता है। आप इसे फिर से आश्चर्यचकित नहीं होंगे! ईमानदारी से, मुझे लगता है कि मेरे साथ भी ऐसा ही हुआ होगा, कई साल पहले।


POSIX संदर्भ जाँच करने के लिए है, लेकिन वास्तव में manके लिए पृष्ठों cpBSD पर (कम से कम, OSX) और की ग्नू संस्करण cp"अधिलेखन" के बारे में इतना स्पष्ट नहीं हैं। यह शब्द केवल विकल्पों पर टिप्पणियों में उपयोग किया जाता है -iऔर -n। Gnu मैनपेज विशेष रूप से एकरूप है, शुरुआत Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.में BSD / Mac मैनपेज कम से कम कहता हैIn the first synopsis form, the cp utility copies the contents of the source_file to the target_file.
dubiousjim

Gnu coreutils जानकारी पृष्ठ शुरू होता है:‘cp’ copies files (or, optionally, directories). The copy is completely independent of the original.
dubiousjim

2
मुझे लगता है कि POSIX 2008 मानक मनाया व्यवहार निर्दिष्ट करता है; मैं एक जवाब जोड़ दूंगा।
दुबेजिम

16

मैं देखता हूं कि POSIX 2013 मानक देखे गए व्यवहार को निर्दिष्ट करता है । इसे कहते हैं:

  1. यदि source_file नियमित फ़ाइल का प्रकार है, तो निम्न कदम उठाए जाएंगे:

    ए। ... यदि dest_file मौजूद है, तो निम्नलिखित कदम उठाए जाएंगे:

    मैं। यदि -iविकल्प प्रभावी होता है, तो cpउपयोगिता मानक त्रुटि के लिए संकेत लिखती है और मानक इनपुट से एक पंक्ति पढ़ती है। यदि प्रतिक्रिया सकारात्मक नहीं है, cpतो source_file के साथ अधिक कुछ नहीं करना चाहिए और किसी भी शेष फाइल पर जाना चाहिए।

    ii। के लिए एक फ़ाइल वर्णनकर्ता dest_file के बराबर कार्यों का निष्पादन द्वारा प्राप्त किया जाएगा open()समारोह POSIX.1-2008 की प्रणाली इंटरफेस मात्रा में परिभाषित का उपयोग कर बुलाया dest_file पथ तर्क के रूप में, और बिटवाइज़ समावेशी ORकी O_WRONLYऔर O_TRUNCके रूप में oflag तर्क।

    iii। यदि फ़ाइल डिस्क्रिप्टर प्राप्त करने का प्रयास विफल हो जाता है और -fविकल्प प्रभावी होता है, cpतो unlink()POSIX.1-2008 के सिस्टम इंटरफेसेस वॉल्यूम में परिभाषित फ़ंक्शन के समतुल्य क्रिया करके फ़ाइल को निकालने का प्रयास करेगा , जिसे पथ तर्क के रूप में dest_file का उपयोग करके बुलाया गया है। यदि यह प्रयास सफल होता है, cpतो चरण 3 बी के साथ जारी रहेगा।

    ...

    घ। Source_file की सामग्री फ़ाइल डिस्क्रिप्टर को लिखी जाएगी। कोई भी लेखन त्रुटि cpमानक त्रुटि के लिए नैदानिक ​​संदेश लिखने और चरण 3e को जारी रखने का कारण होगी ।

    इ। फ़ाइल डिस्क्रिप्टर बंद हो जाएगा।


1
दिलचस्प। आपकी तरह, मैंने माना cpकि mvकिसी भी हार्डलिंक को तोड़ने के लिए इसी तरह के परिणाम होंगे और भाग्य का हिस्सा था। लेकिन अब जब मैं इसके बारे में सोचता हूं, तो इसका मतलब यह होगा कि इसे विशेष रूप unlink(2)से लक्ष्य ( cp -f), या एक अलग नाम वाला अस्थायी बनाना होगा और फिर rename(2)इसे। सीधा कार्यान्वयन केवल ओवरराइट के लिए फ़ाइल को खोलना है, जो कि POSIX की आवश्यकता है। यह बराबर हैcat src > dest
पीटर कॉर्ड्स

2

यदि आप कह सकते हैं, "किसी फ़ाइल को गंतव्य पथ paul पर कॉपी करना भी उसी फ़ाइल (समान इनोड) को अन्य सभी गंतव्य पथों की प्रतिलिपि बनाता है, जो इनोड को साझा करते हैं paul।", मुझे यह कहते हुए खेद है कि आप इस धारणा को नहीं समझते हैं हार्ड लिंक बहुत अच्छी तरह से। अगर मैं सर मैककार्टनी को एक सेब देता हूं, तो मैंने पॉल को एक सेब दिया है, और मैंने जॉन लेनन के गीतकार साथी को एक सेब दिया है। लेकिन मैंने तीन सेब नहीं दिए हैं; मैंने एक ऐसे व्यक्ति को सेब दिया है, जिसके कई नाम / शीर्षक / विवरण हैं।

इसी तरह, जब आप कॉपी georgeकरते हैं paul, तो आप इसे कॉपी भी नहीं कर रहे हैं john। इसके बजाय, आप georgeडेटा को उस फ़ाइल में कॉपी कर रहे हैं जिसका इनकोड paulनिर्देशिका प्रविष्टि द्वारा इंगित किया गया है ।

कदम से कदम:   जब आप करते हैं

echo john > john

आपने एक नई फ़ाइल बनाई है (यह मानते हुए कि johnउस निर्देशिका में पहले से कोई फ़ाइल नहीं है )। या, अधिक सख्ती से बात करने के लिए, यह मान लिया गया johnहै कि उस निर्देशिका में नाम के साथ पहले से ही एक निर्देशिका प्रविष्टि नहीं थी (क्योंकि, कड़ाई से बोलना, निर्देशिका में कोई फ़ाइल नहीं है; केवल निर्देशिका प्रविष्टियाँ, जो इनोड्स को इंगित करती हैं)। तुम्हारे जाने के बाद

cp -l john paul

या

ln john paul

आपने एक नई फ़ाइल नहीं बनाई है; बल्कि, आपने अपनी मौजूदा फ़ाइल को एक नया नाम दिया है। अब आपके पास दो नामों वाली फाइल है: johnऔर paul। और जब आप कहेंगे

cp george paul

आप उस फ़ाइल को ओवरराइट कर रहे हैं । तथ्य यह है कि यह दो नाम है अप्रासंगिक है; इसमें 42 नाम हो सकते हैं, संभवतः उन जगहों पर जहां आप पहुंच भी नहीं सकते हैं, और यह कमांड george\nउन सभी नामों (पथ) के लिए डेटा की प्रतिलिपि नहीं बना रहा होगा ; यह डेटा को एक फ़ाइल में कॉपी कर रहा है जिसमें कई नाम हैं।


1
धन्यवाद। ठीक है, मुझे डराने वाले-उद्धरण-आवश्यक चरित्र के बारे में पता था जो मैं लिख रहा था जैसा कि मैंने लिखा था: johnऔर paulएक ही फ़ाइल के लिए दो पथनाम के रूप में शुरू करें। लेकिन यह सबसे आसान तरीका था जिससे मैं खुद को व्यक्त करने के बारे में सोच सकता था। मुझे नहीं लगता कि एक कड़ी की मात्र धारणा, सही ढंग से समझी गई, दोनों में से किसी भी व्यवहार को (बिना ) तय करती हैcp-l
dubiousjim

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