अगर कोई फाइल बनाई जा सकती है या मैं उसे काट-छाँट / ओवर-राइट कर सकता हूं, तो मैं कैसे जांच सकता हूं?


15

उपयोगकर्ता मेरी स्क्रिप्ट को एक फ़ाइल पथ के साथ कॉल करता है जिसे या तो स्क्रिप्ट में किसी बिंदु पर बनाया या अधिलेखित किया जाएगा, जैसे foo.sh file.txtया foo.sh dir/file.txt

क्रिएट-या-ओवरराइट व्यवहार फ़ाइल को >आउटपुट रीडायरेक्ट ऑपरेटर के दाईं ओर रखने के लिए आवश्यकताओं की तरह है , या इसे एक तर्क के रूप में पारित कर रहा है tee(वास्तव में, इसे एक तर्क के रूप में पारित करना teeवास्तव में मैं क्या कर रहा हूं )।

इससे पहले कि मैं स्क्रिप्ट की चपेट में आऊं, मैं एक उचित जांच करना चाहता हूं कि क्या फाइल बनाई / अधिलेखित की जा सकती है, लेकिन वास्तव में इसे नहीं बनाया गया है। यह जाँच सही नहीं है, और हाँ मुझे एहसास है कि जाँच और बिंदु के बीच स्थिति बदल सकती है जहाँ फ़ाइल वास्तव में लिखी गई है - लेकिन यहाँ मैं एक सर्वोत्तम प्रयास प्रकार के समाधान के साथ ठीक हूँ ताकि मैं जल्दी से बाहर निकल सकूँ उस स्थिति में जब फ़ाइल पथ अमान्य है।

फ़ाइल नहीं बनाई जा सकी कारणों के उदाहरण:

  • फ़ाइल में एक निर्देशिका घटक होता है, dir/file.txtलेकिन निर्देशिका dirमौजूद नहीं है
  • उपयोगकर्ता के पास निर्दिष्ट निर्देशिका में अनुमतियाँ नहीं हैं (या यदि कोई निर्देशिका निर्दिष्ट नहीं की गई है तो CWD)

हां, मुझे एहसास है कि चेकिंग अनुमतियाँ "अप फ्रंट" यूनिक्स तरीका ™ नहीं है , बल्कि मुझे बस ऑपरेशन की कोशिश करनी चाहिए और बाद में माफी मांगनी चाहिए। हालांकि मेरी विशेष स्क्रिप्ट में, यह एक खराब उपयोगकर्ता अनुभव की ओर जाता है और मैं जिम्मेदार घटक को नहीं बदल सकता।


क्या तर्क हमेशा वर्तमान निर्देशिका पर आधारित होगा या उपयोगकर्ता पूर्ण पथ निर्दिष्ट कर सकता है?
jesse_b 22

@Jesse_b - मुझे लगता है कि उपयोगकर्ता एक निरपेक्ष पथ निर्दिष्ट कर सकता है /foo/bar/file.txt। मूल रूप से मैं कमांड लाइन पर जहां पारित किया जाता है tee, tee $OUT_FILEवहां पसंद करने के लिए रास्ता पास करता हूं OUT_FILE। यह दोनों पूर्ण और सापेक्ष पथ के साथ "बस काम" करना चाहिए, है ना?
BeeOnRope 22

@ BeeOnRope, नहीं, आपको tee -- "$OUT_FILE"कम से कम आवश्यकता होगी । क्या होगा यदि फ़ाइल पहले से मौजूद है या मौजूद है, लेकिन एक नियमित फ़ाइल (निर्देशिका, सिमलिंक, फिफो) नहीं है?
स्टीफन चेज़लस

@ स्टीफनचेज़ेलस - अच्छी तरह से मैं उपयोग कर रहा हूं tee "${OUT_FILE}.tmp"। यदि फ़ाइल पहले से मौजूद है, तो teeअधिलेखित हो जाती है, जो इस मामले में वांछित व्यवहार है। यदि यह एक निर्देशिका है, teeतो असफल हो जाएगा (मुझे लगता है)। सिम्लिंक मैं 100% निश्चित नहीं हूं?
BeeOnRope

जवाबों:


11

स्पष्ट परीक्षा होगी:

if touch /path/to/file; then
    : it can be created
fi

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

if touch /path/to/file; then
    rm /path/to/file
fi

लेकिन यह एक ऐसी फ़ाइल को हटा देगा जो पहले से मौजूद थी, जिसे आप शायद नहीं चाहते हैं।

हालाँकि, हमारे पास इसका एक तरीका है:

if mkdir /path/to/file; then
    rmdir /path/to/file
fi

आपके पास उस निर्देशिका में किसी अन्य ऑब्जेक्ट के समान नाम वाली निर्देशिका नहीं हो सकती है। मैं ऐसी स्थिति के बारे में नहीं सोच सकता जिसमें आप एक निर्देशिका बनाने में सक्षम हों, लेकिन एक फ़ाइल नहीं बना पाएंगे। इस परीक्षण के बाद, आपकी स्क्रिप्ट एक पारंपरिक बनाने के लिए स्वतंत्र होगी /path/to/fileऔर इसके साथ जो कुछ भी करना है वह करें।


2
बहुत करीने से इतने सारे मुद्दों को संभालता है! यह बताते हुए कि असामान्य समाधान आपके उत्तर की लंबाई को अच्छी तरह से पार कर सकता है। :-)
jpaugh

मैंने if mkdir /var/run/lockdirलॉकिंग टेस्ट के रूप में भी उपयोग किया है। यह परमाणु है, जबकि if ! [[ -f /var/run/lockfile ]]; then touch /var/run/lockfileपरीक्षण के बीच में समय का एक छोटा टुकड़ा है और touchजहां प्रश्न में स्क्रिप्ट का एक और उदाहरण शुरू हो सकता है।
डोपघोटी

8

मैं जो इकट्ठा कर रहा हूं, आप उपयोग करते समय जांचना चाहते हैं

tee -- "$OUT_FILE"

(ध्यान दें --या यह फ़ाइल नामों के लिए काम नहीं करेगा जो शुरू होता है -), teeलिखने के लिए फ़ाइल खोलने में सफल होगा।

वह है वह:

  • फ़ाइल पथ की लंबाई PATH_MAX सीमा से अधिक नहीं है
  • फ़ाइल मौजूद है (सिम्लिंक रिज़ॉल्यूशन के बाद) और टाइप डायरेक्टरी का नहीं है और आपने इसे लिखने की अनुमति दी है।
  • यदि फ़ाइल मौजूद नहीं है, तो फ़ाइल का dirname एक निर्देशिका के रूप में (सिमलिंक रिज़ॉल्यूशन के बाद) मौजूद है और आपके पास इसे लिखने और खोजने की अनुमति है और फ़ाइल नाम उस फ़ाइल सिस्टम की NAME_MAX सीमा से अधिक नहीं है जो निर्देशिका में रहती है।
  • या फ़ाइल एक सिमलिंक है जो एक ऐसी फ़ाइल को इंगित करता है जो मौजूद नहीं है और सिम्लिंक लूप नहीं है लेकिन ऊपर दिए गए मानदंडों को पूरा करता है

हम अभी के लिए फ़ाइल सिस्टम जैसे vfat, ntfs या hfsplus को अनदेखा करेंगे जिनकी बाइट मान फ़ाइल नाम में सीमाएँ हैं, डिस्क कोटा, प्रक्रिया सीमा, सेलिनक्स, एपरमोर या रास्ते में अन्य सुरक्षा तंत्र, पूर्ण प्रणाली, कोई इनोड शेष नहीं, डिवाइस ऐसी फ़ाइलें जो किसी कारण या किसी अन्य तरीके से नहीं खोली जा सकती हैं, वे फ़ाइलें जो वर्तमान में निष्पादन योग्य हैं, जो किसी प्रक्रिया पते स्थान में मैप की जाती हैं, जो सभी फ़ाइल को खोलने या बनाने की क्षमता को प्रभावित कर सकती हैं।

के साथ zsh:

zmodload zsh/system
tee_would_likely_succeed() {
  local file=$1 ERRNO=0 LC_ALL=C
  if [ -d "$file" ]; then
    return 1 # directory
  elif [ -w "$file" ]; then
    return 0 # writable non-directory
  elif [ -e "$file" ]; then
    return 1 # exists, non-writable
  elif [ "$errnos[ERRNO]" != ENOENT ]; then
    return 1 # only ENOENT error can be recovered
  else
    local dir=$file:P:h base=$file:t
    [ -d "$dir" ] &&    # directory
      [ -w "$dir" ] &&  # writable
      [ -x "$dir" ] &&  # and searchable
      (($#base <= $(getconf -- NAME_MAX "$dir")))
    return
  fi
}

में bashया किसी बॉर्न-जैसा शेल, बस की जगह

zmodload zsh/system
tee_would_likely_succeed() {
  <zsh-code>
}

साथ में:

tee_would_likely_succeed() {
  zsh -s -- "$@" << 'EOF'
  zmodload zsh/system
  <zsh-code>
EOF
}

यहां zshविशिष्ट विशेषताएं हैं $ERRNO(जो अंतिम सिस्टम कॉल के त्रुटि कोड को उजागर करती हैं) और $errnos[]संबंधित मानक सी मैक्रो नामों का अनुवाद करने के लिए साहचर्य सरणी। और $var:h(csh से) और $var:P(zsh 5.3 या इसके बाद के संस्करण की जरूरत है)।

बैश में अभी तक समान विशेषताएं नहीं हैं।

$file:hसाथ बदला जा सकता dir=$(dirname -- "$file"; echo .); dir=${dir%??}या, जीएनयू साथ dirname: IFS= read -rd '' dir < <(dirname -z -- "$file")

के लिए $errnos[ERRNO] == ENOENT, एक दृष्टिकोण ls -Ldफ़ाइल पर चलाया जा सकता है और यह जांच सकता है कि त्रुटि संदेश ENOENT त्रुटि से मेल खाती है या नहीं। हालांकि मज़बूती से और आंशिक रूप से यह करना मुश्किल है।

एक दृष्टिकोण हो सकता है:

msg_for_ENOENT=$(LC_ALL=C ls -d -- '/no such file' 2>&1)
msg_for_ENOENT=${msg_for_ENOENT##*:}

(यह मानते हुए कि त्रुटि संदेश के अनुवाद के साथ समाप्त होताsyserror() है ENOENTऔर उस अनुवाद में शामिल नहीं है :) और फिर, के बजाय [ -e "$file" ], करें:

err=$(ls -Ld -- "$file" 2>&1)

और साथ एक त्रुटि के लिए जाँच करें

case $err in
  (*:"$msg_for_ENOENT") ...
esac

$file:Pभाग trickiest में प्राप्त करने के लिए bashविशेष रूप से FreeBSD पर,।

FreeBSD में एक realpathकमांड और एक readlinkकमांड होता है जो एक -fविकल्प को स्वीकार करता है , लेकिन उनका उपयोग उन मामलों में नहीं किया जा सकता है जहां फ़ाइल एक सिमलिंक है जो हल नहीं करता है। यही कारण है कि के साथ एक ही है perlकी Cwd::realpath()

pythonके os.path.realpath()समान काम करने के लिए प्रकट होता है zsh $file:P, इसलिए यह मानते हुए कि कम से कम एक संस्करण pythonस्थापित है और यह एक pythonआदेश है जो उनमें से एक को संदर्भित करता है (जो कि FreeBSD पर नहीं दिया गया है), आप कर सकते हैं:

dir=$(python -c '
import os, sys
print(os.path.realpath(sys.argv[1]) + ".")' "$dir") || return
dir=${dir%.}

लेकिन फिर, आप पूरी बात भी कर सकते हैं python

या आप उन सभी कोने के मामलों को नहीं संभालने का फैसला कर सकते हैं।


हां, आपने मेरी मंशा को सही ढंग से समझा। वास्तव में, मूल प्रश्न स्पष्ट नहीं था: मैंने मूल रूप से फ़ाइल बनाने के बारे में बात की थी , लेकिन वास्तव में मैं इसका उपयोग कर रहा हूँ teeइसलिए आवश्यकता वास्तव में यह है कि फ़ाइल मौजूद नहीं है, तो इसे बनाया जा सकता है या इसे शून्य और ओवरराइट किया जा सकता है अगर यह करता है (या फिर अन्य teeकि संभालता है)।
BeeOnRope

ऐसा लगता है कि आपके अंतिम संपादन ने प्रारूपण को मिटा दिया
डी बेन नोबल

धन्यवाद, @ bishop, @ D.BenKnoble, संपादन देखें।
स्टीफन चेज़ेलस

1
@DennisWilliamson, हाँ, एक शेल प्रोग्रामों को आमंत्रित करने के लिए एक उपकरण है, और आपकी स्क्रिप्ट में आपके द्वारा इनवॉइस करने वाले प्रत्येक प्रोग्राम को आपकी स्क्रिप्ट को काम करने के लिए स्थापित किया जाना है, जो बिना कहे चला जाता है। macOS डिफ़ॉल्ट रूप से इंस्टॉल किए गए बैश और zsh दोनों के साथ आता है। FreeBSD न तो साथ आता है। ओपी के पास बैश में ऐसा करने के लिए एक अच्छा कारण हो सकता है, शायद यह कुछ ऐसा है जो वे पहले से लिखे बैश स्क्रिप्ट में जोड़ना चाहते हैं।
स्टीफन चेजलस

1
@ पका, फिर, एक शेल एक दुभाषिया है। आप देखेंगे कि यहाँ लिखे गए कई शेल कोड अंश अन्य भाषाओं के दुभाषियों को आमंत्रित करते हैं perl, जैसे awk, sedया python(या फिर sh, bash...)। शेल स्क्रिप्टिंग कार्य के लिए सर्वश्रेष्ठ कमांड का उपयोग करने के बारे में है। यहाँ भी perlएक समान नहीं है zshकी $var:P(अपने Cwd::realpathबीएसडी की तरह बर्ताव करता है realpathया readlink -fयह जीएनयू की तरह व्यवहार करने के लिए आप चाहते हैं चाहते हैं, जबकि readlink -fया pythonके os.path.realpath())
स्टीफन Chazelas

6

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

कुछ इस तरह:

#!/bin/bash

# Open the file for read/write, so it doesn't get
# truncated just yet (to preserve the contents in
# case the initial checks fail.)
exec 3<>dir/file.txt || {
    echo "Error creating dir/file.txt" >&2
    exit 1
}

# Long checks here...
check_ok || {
    echo "Failed checks" >&2
    # cleanup file before bailing out
    rm -f dir/file.txt
    exit 1
}

# We're ready to write, first truncate the file.
# Use "truncate(1)" from coreutils, and pass it
# /dev/fd/3 so the file doesn't need to be reopened.
truncate -s 0 /dev/fd/3

# Now populate the file, use a redirection to write
# to the previously opened file descriptor.
populate_contents >&3

आप trapत्रुटि पर फ़ाइल को साफ करने के लिए भी उपयोग कर सकते हैं , यह एक आम बात है।

इस तरह, आप उन अनुमतियों के लिए एक वास्तविक जाँच प्राप्त कर सकते हैं, जिन्हें आप फ़ाइल बनाने में सक्षम होंगे, जबकि एक ही समय में यह पर्याप्त रूप से जल्दी प्रदर्शन करने में सक्षम है कि यदि आप विफल रहता है तो आपने लंबे समय तक चेक के इंतजार में समय नहीं बिताया है।


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

जब हम सामग्री को बदलने के लिए तैयार होते हैं, तो हमें पहले फ़ाइल को ट्रंक करना होगा (अन्यथा यदि हम फ़ाइल में पहले की तुलना में कम बाइट्स लिख रहे हैं, तो अनुगामी बाइट्स वहां रहेंगे।) हम ट्रंकट (1) का उपयोग कर सकते हैं। उस उद्देश्य के लिए कोरुटिल्स से कमांड, और हम इसे ओपन फाइल डिस्क्रिप्टर पास कर सकते हैं जो हमारे पास है ( /dev/fd/3छद्म फाइल का उपयोग करके ) इसलिए इसे फाइल को फिर से खोलने की आवश्यकता नहीं है। (फिर, तकनीकी रूप से कुछ सरल जैसे : >dir/file.txtकि शायद काम करेगा, लेकिन फ़ाइल को फिर से खोलने के लिए नहीं होना एक अधिक सुंदर विकल्प है)।


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

1
@BeeOnRope एक अन्य विकल्प जो फ़ाइल को बंद नहीं करेगा, वह इसके लिए कुछ भी करने की कोशिश नहीं करेगा: echo -n >>fileया true >> file। बेशक, ext4 में एपेंड-ओनली फाइलें हैं, लेकिन आप उस झूठी सकारात्मक के साथ रह सकते हैं।
मोवी

1
@BeeOnRope यदि आपको (a) मौजूदा फ़ाइल या (b) a (पूर्ण) नई फ़ाइल को संरक्षित करने की आवश्यकता है, तो यह आपके द्वारा पूछे गए सवाल से अलग है। इसका एक अच्छा उत्तर यह है कि नई फ़ाइल my-file.txt.backupबनाने से पहले मौजूदा फ़ाइल को एक नए नाम (जैसे ) में ले जाया जाए । एक अन्य समाधान यह है कि नई फ़ाइल को उसी फ़ोल्डर में एक अस्थायी फ़ाइल में लिखें, और फिर बाकी स्क्रिप्ट के सफल होने के बाद उसे पुरानी फ़ाइल पर कॉपी करें --- यदि वह अंतिम ऑपरेशन विफल हो गया, तो उपयोगकर्ता मैन्युअल रूप से बिना खोए समस्या को ठीक कर सकता है उसकी या उसकी प्रगति।
jpaugh

1
@BeeOnRope यदि आप "परमाणु प्रतिस्थापित" मार्ग (जो एक अच्छा है!) के लिए जाते हैं, तो आम तौर पर आप अंतिम फ़ाइल के रूप में एक ही निर्देशिका में अस्थायी फ़ाइल लिखना चाहते हैं (उन्हें नाम बदलने के लिए एक ही फाइल सिस्टम में होना चाहिए। (2) सफल होने के लिए) और एक अद्वितीय नाम का उपयोग करें (इसलिए यदि स्क्रिप्ट के दो उदाहरण चल रहे हैं, तो वे एक-दूसरे की अस्थायी फ़ाइलों को बंद नहीं करेंगे।) उसी निर्देशिका में लिखने के लिए एक अस्थायी फ़ाइल खोलना आमतौर पर एक अच्छा संकेत है। 'बाद में इसका नाम बदलने में सक्षम होंगे (ठीक है, सिवाय इसके कि अगर अंतिम लक्ष्य मौजूद है और एक निर्देशिका है), तो कुछ हद तक यह आपके प्रश्न को भी संबोधित करता है।
filbranden

1
@jpaugh - मैं ऐसा करने के लिए काफी अनिच्छुक हूं। यह अनिवार्य रूप से मेरे उच्च स्तर की समस्या को हल करने की कोशिश करने वाले उत्तरों को जन्म देगा, जो उन समाधानों को स्वीकार कर सकते हैं जिनका "प्रश्न मैं कैसे जांच सकता हूं ..." से कोई लेना-देना नहीं है। मेरी उच्च स्तरीय समस्या चाहे जो भी हो, मुझे लगता है कि यह प्रश्न अकेले ही खड़ा है क्योंकि आप यथोचित रूप से कुछ करना चाहते हैं। यह उन लोगों के लिए अनुचित होगा जो उस विशिष्ट प्रश्न का उत्तर दे रहे हैं यदि मैंने इसे "मेरी स्क्रिप्ट के साथ होने वाले इस विशिष्ट मुद्दे को हल करने के लिए" बदल दिया है। मैंने उन विवरणों को यहां शामिल किया क्योंकि मुझसे पूछा गया था, लेकिन मैं प्राथमिक प्रश्न को बदलना नहीं चाहता।
BeeOnRope

4

मुझे लगता है कि डोपगोटी का समाधान बेहतर है लेकिन यह भी काम करना चाहिए:

file=$1
if [[ "${file:0:1}" == '/' ]]; then
    dir=${file%/*}
elif [[ "$file" =~ .*/.* ]]; then
    dir="$(PWD)/${file%/*}"
else
    dir=$(PWD)
fi

if [[ -w "$dir" ]]; then
    echo "writable"
    #do stuff with writable file
else
    echo "not writable"
    #do stuff without writable file
fi

यदि तर्क पूर्ण पथ (शुरू होता है /) के साथ निर्माण करता है और पहले dirचर को अंतिम पथ तक ले जाता है, तो चेक चेक करता है /। अन्यथा यदि तर्क के साथ शुरू नहीं होता है, /लेकिन इसमें /(उप निर्देशिका निर्दिष्ट करना) होता है, तो यह dirवर्तमान कार्यशील निर्देशिका + उप निर्देशिका पथ पर सेट हो जाएगा । अन्यथा यह वर्तमान कार्यशील निर्देशिका को मानता है। यह तब जांचता है कि क्या निर्देशिका राइट है।


4

testनीचे उल्लिखित सामान्य कमांड का उपयोग करने के बारे में क्या ?

FILE=$1

DIR=$(dirname $FILE) # $DIR now contains '.' for file names only, 'foo' for 'foo/bar'

if [ -d $DIR ] ; then
  echo "base directory $DIR for file exists"
  if [ -e $FILE ] ; then
    if [ -w $FILE ] ; then
      echo "file exists, is writeable"
    else
      echo "file exists, NOT writeable"
    fi
  elif [ -w $DIR ] ; then
    echo "directory is writeable"
  else
    echo "directory is NOT writeable"
  fi
else
  echo "can NOT create file in non-existent directory $DIR "
fi

मैंने लगभग इस जवाब को दोहराया! अच्छा परिचय, लेकिन आप उल्लेख कर सकते हैं man test, और यह [ ]परीक्षण के बराबर है (अब सामान्य ज्ञान नहीं)। यहाँ एक-लाइनर है जो मैं अपने अवर उत्तर में उपयोग करने वाला था, सटीक मामले को कवर करने के लिए, पोस्टीरिटी के लिए:if [ -w $1] && [ ! -d $1 ] ; then echo "do stuff"; fi
आयरन ग्रेमलिन

4

आपने बताया कि उपयोगकर्ता अनुभव आपके प्रश्न को चला रहा था। मैं UX कोण से उत्तर दूंगा, क्योंकि आपको तकनीकी पक्ष में अच्छे उत्तर मिले हैं।

चेक-अप का प्रदर्शन करने के बजाय, परिणाम को अस्थायी फ़ाइल में लिखने के बारे में , आखिर में, उपयोगकर्ता की इच्छित फ़ाइल में परिणाम डालते हुए? पसंद:

userfile=${1:?Where would you like the file written?}
tmpfile=$(mktemp)

# ... all the complicated stuff, writing into "${tmpfile}"

# fill user's file, keeping existing permissions or creating anew
# while respecting umask
cat "${tmpfile}" > "${userfile}"
if [ 0 -eq $? ]; then
    rm "${tmpfile}"
else
    echo "Couldn't write results into ${userfile}." >&2
    echo "Results available in ${tmpfile}." >&2
    exit 1
fi

इस दृष्टिकोण के साथ अच्छा है: यह सामान्य खुश पथ परिदृश्य में वांछित ऑपरेशन का उत्पादन करता है, परीक्षण-और-सेट एटमॉसिस समस्या को साइड-स्टेप करता है, यदि आवश्यक हो तो बनाते समय लक्ष्य फ़ाइल की अनुमति सुरक्षित रखता है और लागू करने के लिए मृत है।

नोट: हमने उपयोग किया था mv, हम अस्थायी फ़ाइल की अनुमतियाँ रखेंगे - हम ऐसा नहीं चाहते हैं, मुझे लगता है: हम अनुमतियों को लक्ष्य फ़ाइल पर सेट के रूप में रखना चाहते हैं।

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


वास्तव में, यह कमोबेश मैं अब कर रहा हूं। मैं अधिकांश परिणामों को एक अस्थायी फ़ाइल में लिखता हूं और फिर अंत में अंतिम प्रसंस्करण चरण करता हूं और अंतिम फ़ाइल के लिए परिणाम लिखता हूं। समस्या यह है कि मैं जल्दी (स्क्रिप्ट की शुरुआत में) जमानत करना चाहता हूं अगर वह अंतिम चरण विफल होने की संभावना है। स्क्रिप्ट मिनटों या घंटों तक अनअटेंडेड चल सकती है, इसलिए आप वास्तव में सामने वाले को जानना चाहते हैं कि वह असफल है!
BeeOnRope

ज़रूर, लेकिन ऐसे कई तरीके हैं जो विफल हो सकते हैं: डिस्क भर सकती है, अपस्ट्रीम डायरेक्टरी को हटाया जा सकता है, अनुमतियां बदल सकती हैं, कुछ अन्य महत्वपूर्ण सामानों के लिए लक्ष्य फ़ाइल का उपयोग किया जा सकता है और उपयोगकर्ता भूल गया कि उसने उसी फ़ाइल को इसके द्वारा नष्ट कर दिया है। ऑपरेशन। अगर हम शुद्ध UX के नजरिए से इस बारे में बात करते हैं, तो शायद सही काम इसे एक नौकरी प्रस्तुत करने की तरह है: अंत में, जब आप जानते हैं कि इसे पूरा करने के लिए सही ढंग से काम किया है, तो बस उपयोगकर्ता को बताएं कि परिणामी सामग्री कहां रहती है और प्रस्ताव उन्हें खुद इसे स्थानांतरित करने के लिए एक सुझाव दिया गया आदेश।
बिशप

सिद्धांत रूप में, हाँ अनंत तरीके हैं जो विफल हो सकते हैं। व्यवहार में, इस समय का भारी बहुमत विफल हो जाता है क्योंकि प्रदान किया गया मार्ग वैध नहीं है। मैं यथोचित रूप से कुछ दुष्ट उपयोगकर्ता को कार्य के बीच में कार्य को तोड़ने के लिए FS को संशोधित करने के लिए समवर्ती रूप से रोक नहीं सकता, लेकिन मैं निश्चित रूप से एक अमान्य या नहीं लिखने योग्य पथ के # 1 विफलता कारण की जांच कर सकता हूं।
BeeOnRope

2

टीएल, डॉ:

: >> "${userfile}"

इसके विपरीत <> "${userfile}"या touch "${userfile}", यह फ़ाइल के टाइमस्टैम्प में कोई भी संशोधन नहीं करेगा और यह केवल लेखन फ़ाइलों के साथ भी काम करेगा।


ओपी से:

मैं एक उचित जांच करना चाहता हूं कि क्या फाइल बनाई जा सकती है / अधिलेखित की जा सकती है, लेकिन वास्तव में इसे नहीं बनाया जा सकता है।

और आपकी टिप्पणी से मेरे उत्तर तक एक UX परिप्रेक्ष्य से :

इस समय का भारी बहुमत विफल रहता है क्योंकि प्रदान किया गया मार्ग वैध नहीं है। मैं यथोचित रूप से कुछ दुष्ट उपयोगकर्ता को कार्य के बीच में काम को तोड़ने के लिए एफएस को संशोधित करने वाले कुछ समवर्ती उपयोगकर्ता को नहीं रोक सकता, लेकिन मैं निश्चित रूप से एक अमान्य या नहीं लिखने योग्य पथ के # 1 विफलता कारण की जांच कर सकता हूं।

एकमात्र विश्वसनीय परीक्षण open(2)फ़ाइल के लिए है, क्योंकि केवल वह ही लेखन योग्यता के बारे में हर प्रश्न को हल करता है: पथ, स्वामित्व, फाइल सिस्टम, नेटवर्क, सुरक्षा संदर्भ, आदि। कोई भी अन्य परीक्षा लेखन क्षमता के कुछ हिस्से को संबोधित करेगी, लेकिन अन्य नहीं। यदि आप परीक्षणों का एक सबसेट चाहते हैं, तो आपको अंततः यह चुनना होगा कि आपके लिए क्या महत्वपूर्ण है।

लेकिन यहाँ एक और विचार है। मैं जो कुछ समझता हूं:

  1. सामग्री निर्माण प्रक्रिया लंबे समय से चल रही है, और
  2. लक्ष्य फ़ाइल को एक सुसंगत स्थिति में छोड़ दिया जाना चाहिए।

आप # 1 के कारण यह प्री-चेक करना चाहते हैं, और आप # 2 की वजह से किसी मौजूदा फ़ाइल के साथ फ़ील नहीं करना चाहते हैं। तो आप केवल शेल को ऐपेंड के लिए फ़ाइल खोलने के लिए क्यों नहीं कहते हैं, लेकिन वास्तव में कुछ भी नहीं जोड़ते हैं?

$ tree -ps
.
├── [dr-x------        4096]  dir_r
├── [drwx------        4096]  dir_w
├── [-r--------           0]  file_r
└── [-rw-------           0]  file_w

$ for p in file_r dir_r/foo file_w dir_w/foo; do : >> $p; done
-bash: file_r: Permission denied
-bash: dir_r/foo: Permission denied

$ tree -ps
.
├── [dr-x------        4096]  dir_r
├── [drwx------        4096]  dir_w
   └── [-rw-rw-r--           0]  foo
├── [-r--------           0]  file_r
└── [-rw-------           0]  file_w

हुड के तहत, यह वास्तव में वांछित के रूप में लेखनी का सवाल हल करता है:

open("dir_w/foo", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

लेकिन फ़ाइल की सामग्री या मेटाडेटा को संशोधित किए बिना। अब, हाँ, यह दृष्टिकोण:

  • आपको यह नहीं बताता कि क्या फ़ाइल केवल एपेंड है, जो आपके सामग्री निर्माण के अंत में इसे अपडेट करने के बारे में जाने पर एक समस्या हो सकती है। आप इसका पता लगा सकते हैं, एक हद तक, इसके lsattrअनुसार और प्रतिक्रिया कर सकते हैं।
  • ऐसी फ़ाइल बनाता है जो पहले मौजूद नहीं थी, अगर ऐसी स्थिति है: इसे एक चयनात्मक के साथ कम करें rm

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

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