ব্যাশে কোনও ফাইল তৈরি করা বা ছাঁটাই / ওভাররাইট করা যায় কিনা তা আমি কীভাবে পরীক্ষা করতে পারি?


15

ব্যবহারকারী আমার স্ক্রিপ্টটিকে কোনও ফাইলের পাথ দিয়ে কল করে যা স্ক্রিপ্টের কোনও পর্যায়ে তৈরি বা ওভাররাইট করা হবে, যেমন foo.sh file.txtবা foo.sh dir/file.txt

তৈরি বা ওভাররাইট আচরণটি অনেকটা >আউটপুট পুনঃনির্দেশ অপারেটরের ডানদিকে ফাইল রাখার প্রয়োজনীয়তার মতো , বা এটি একটি আর্গুমেন্ট হিসাবে পাস করার জন্য tee(বাস্তবে, এটি একটি আর্গুমেন্ট হিসাবে এটি পাস করার জন্য)tee করা ঠিক আমি যা করছি )।

আমি স্ক্রিপ্টের সাহস ঢোকা, আমি একটি যুক্তিসঙ্গত চেক করতে ফাইল যদি চান করতে পারেন তৈরি করা / ওভাররাইট, কিন্তু আসলে এটি তৈরি নয়। এই চেকটি নিখুঁত হতে হবে না, এবং হ্যাঁ আমি বুঝতে পারি যে পরিস্থিতিটি চেক এবং ফাইলটি যেখানে লেখা আছে ঠিক সেখানে পয়েন্টের মধ্যে পরিবর্তিত হতে পারে - তবে আমি সর্বোত্তম চেষ্টা করেই ঠিক আছি ধরণের সমাধান যাতে আমি তাড়াতাড়ি জামিন দিতে পারি I এই ক্ষেত্রে ফাইলের পথটি অবৈধ।

ফাইলটি তৈরি করতে না পারার কারণ:

  • ফাইলটিতে একটি ডিরেক্টরি উপাদান রয়েছে, dir/file.txtতবে ডিরেক্টরিটি dirবিদ্যমান নেই
  • নির্দিষ্ট ডিরেক্টরিতে ব্যবহারকারীর লেখার অনুমতি নেই (অথবা কোনও ডিরেক্টরি নির্দিষ্ট না থাকলে CWD)

হ্যাঁ, আমি বুঝতে পারি যে "সামনের দিকে" অনুমতিগুলি পরীক্ষা করা ইউনিক্স ওয়ে নয়, বরং আমার কেবল অপারেশনটি চেষ্টা করা উচিত এবং পরে ক্ষমা চাইতে হবে ask তবে আমার বিশেষ স্ক্রিপ্টে এটি ব্যবহারকারীর খারাপ অভিজ্ঞতার দিকে নিয়ে যায় এবং আমি দায়বদ্ধ উপাদানটি পরিবর্তন করতে পারি না।


যুক্তিটি কি সর্বদা বর্তমান ডিরেক্টরি ভিত্তিক হবে বা ব্যবহারকারী কোনও পুরো পথ নির্দিষ্ট করতে পারে?
jesse_b

@ জেসি_বি - আমি মনে করি যে ব্যবহারকারী কোনও নিখুঁত পথ নির্দিষ্ট করতে পারে /foo/bar/file.txt। মূলত আমি কমান্ড লাইনে কোথায় পাস হবে তা teeপছন্দ করার পথটি পাস করি । এটি "নিখুঁত এবং আপেক্ষিক" উভয় পথেই ঠিক কাজ করবে? tee $OUT_FILEOUT_FILE
BeeOnRope

@ বিঅনরোপ, আপনার tee -- "$OUT_FILE"কমপক্ষে দরকার নেই । যদি ফাইলটি ইতিমধ্যে বিদ্যমান বা উপস্থিত থাকে তবে নিয়মিত ফাইল না হয় তবে (ডিরেক্টরি, সিএমলিংক, ফিফো)?
স্টাফেন চেজেলাস

@ স্টাফেনচেজেলাস - ভালভাবে আমি ব্যবহার করছি tee "${OUT_FILE}.tmp"। যদি ফাইলটি ইতিমধ্যে বিদ্যমান থাকে তবে teeওভাররাইট করে, যা এই ক্ষেত্রে পছন্দসই আচরণ। যদি এটি ডিরেক্টরি হয় teeতবে ব্যর্থ হবে (আমার মনে হয়)। syMLink আমি 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 সীমা অতিক্রম করবে না
  • ফাইলটি বিদ্যমান (সিমিলিং রেজোলিউশনের পরে) এবং এটি টাইপ ডিরেক্টরি নয় এবং আপনার এতে লেখার অনুমতি রয়েছে।
  • যদি ফাইলটি বিদ্যমান না থাকে তবে ফাইলটির ডাইরনাম একটি ডিরেক্টরি হিসাবে উপস্থিত রয়েছে (সিমলিংক রেজোলিউশনের পরে) এবং এতে আপনার লেখার এবং অনুসন্ধানের অনুমতি রয়েছে এবং ফাইলটির নামের দৈর্ঘ্য ডিরেক্টরিতে থাকা ফাইল সিস্টেমের NAME_MAX সীমা অতিক্রম করে না।
  • বা ফাইলটি এমন একটি সিমিলিংক যা কোনও ফাইলকে নির্দেশ করে যা উপস্থিত নেই এবং এটি কোনও সিএমিলিং লুপ নয় তবে কেবল উপরের মানদণ্ডগুলি পূরণ করে

ভিফ্যাট, এনটিএফএস বা এইচএফএসপ্লাসের মতো ফাইল সিস্টেমগুলির জন্য আমরা এখন অবহেলা করব যা বাইট মান ফাইলের নামগুলির মধ্যে সীমাবদ্ধতা রয়েছে, ডিস্ক কোটা, প্রক্রিয়া সীমা, সেলিনাক্স, অ্যাপারমোর বা অন্যান্য সুরক্ষা ব্যবস্থা, পুরো ফাইল সিস্টেম, কোনও ইনোড বাম, ডিভাইস যে ফাইলগুলি যে কারণে বা অন্য কোনও কারণে খোলা যায় না, এক্সিকিউটেবল এমন ফাইলগুলি বর্তমানে কিছু প্রক্রিয়া ঠিকানার জায়গাতে ম্যাপ করা থাকে যার সবগুলি ফাইল খোলার বা তৈরি করার ক্ষমতাকেও প্রভাবিত করতে পারে।

সহ 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(সিএসএস থেকে) এবং$var:P (চাহিদা zsh 5.3 অথবা উপরে)।

বাশ এখনও সমতুল্য বৈশিষ্ট্য নেই।

$file:hdir=$(dirname -- "$file"; echo .); dir=${dir%??}GNU বা এর সাথে প্রতিস্থাপন করা যেতে পারে 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)

এবং এর সাথে একটি ENOENT ত্রুটি পরীক্ষা করুন

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

$file:Pঅংশ trickiest মধ্যে অর্জন করা হল bashবিশেষত FreeBSD 'র উপর।

ফ্রিবিএসডি-র একটি realpathকমান্ড এবং একটি readlinkকমান্ড রয়েছে যা একটি -fবিকল্প গ্রহণ করে , তবে ফাইলগুলি এমন একটি সিমিলিংক রয়েছে যা সমাধান করে না এমন ক্ষেত্রে সেগুলি ব্যবহার করা যাবে না। যে সঙ্গে একই perl'র Cwd::realpath()

pythonএর মতো os.path.realpath()একইরকম কাজ করতে দেখা zsh $file:Pযাচ্ছে, সুতরাং ধরে নিই যে কমপক্ষে একটি সংস্করণ pythonইনস্টল করা আছে এবং একটি pythonআদেশ রয়েছে যা তাদের মধ্যে একটির (যা ফ্রিবিএসডি তে প্রদত্ত নয়) আপনি করতে পারেন:

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

তবে তারপরে, আপনি পাশাপাশি পুরো জিনিসটি করতে পারেন python

অথবা আপনি সিদ্ধান্ত নিতে পারেন যে এই সমস্ত কোণার কেসগুলি পরিচালনা করবেন না।


হ্যাঁ, আপনি আমার উদ্দেশ্যটি সঠিকভাবে বুঝতে পেরেছিলেন। প্রকৃতপক্ষে, আসল প্রশ্নটি অস্পষ্ট ছিল: আমি মূলত ফাইলটি তৈরি করার বিষয়ে বলেছিলাম , তবে আসলে আমি এটি ব্যবহার করছি teeতাই প্রয়োজনীয়তাটি হ'ল ফাইলটি উপস্থিত না থাকলে তৈরি করা যেতে পারে, বা শূন্যে কাটা ও ওভাররাইট করা যেতে পারে যদি এটি করে (বা অন্যথায় এটি teeপরিচালনা করে)।
BeeOnRope

দেখে মনে হচ্ছে আপনার শেষ সম্পাদনাটি বিন্যাসটি মুছে দিয়েছে
ডি বেন নোবল

ধন্যবাদ, @ বিশপ, @ ডি.বেনকনবল, সম্পাদনা দেখুন।
স্টাফেন চেজেলাস

1
@ ডেনিসউইলিইমসন, আচ্ছা হ্যাঁ, একটি শেল হল প্রোগ্রামগুলি আহ্বান করার একটি সরঞ্জাম এবং আপনি আপনার স্ক্রিপ্টে যে সমস্ত প্রোগ্রামটি আহ্বান করেন তা আপনার স্ক্রিপ্টের কাজ করার জন্য ইনস্টল করতে হবে, এটি বিনা কথা বলে চলে। ম্যাকোস ডিফল্টরূপে ইনস্টল করা বাশ এবং zsh উভয়ই সঙ্গে আসে। ফ্রিবিএসডি কেউই আসে না। ওপেশের ব্যাশটিতে এটি করার ইচ্ছা করার একটি ভাল কারণ থাকতে পারে, সম্ভবত এটি এটি ইতিমধ্যে লিখিত বাশ স্ক্রিপ্টে যুক্ত করতে চান।
স্টাফেন চেজেলাস

1
@ পাইপ, আবারও, একটি শেল একটি কমান্ড ইন্টারপ্রেটার। আপনি অনেক শেল কোড এখানে লেখা ডাকা অন্যান্য ভাষায় দোভাষী পছন্দ উদ্ধৃতাংশ দেখতে পাবেন perl, awk, sedবা python(অথবা এমনকি sh, bash...)। শেল স্ক্রিপ্টিংটি কাজের জন্য সেরা কমান্ডটি ব্যবহার করা সম্পর্কে। এখানে এমনকি perlএকটি সমতুল্য নেই zsh'র $var:P(তার Cwd::realpathবাসদ মত আচরণ realpathবা readlink -fএটা গনুহ মত আচরণ করতে চান চাই যখন readlink -fবা pythonএর os.path.realpath())
Stéphane 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পুনর্নির্দেশটি ব্যবহার করুন যা এই মুহুর্তে ফাইলটি কাটাবে না। (আমরা ফাইলটি পড়ার বিষয়ে চিন্তা করি না, এটি কেবল একটি কর্মচঞ্চল তাই আমরা এটিকে ছাঁটাই করি না with>> এটি যোগ করা সম্ভবত খুব বেশি কাজ করবে, তবে আমি ও_এপিএপিএন্ডের পতাকাটি বাইরে রেখে এইটিকে আরও কিছুটা মার্জিত বলে মনে করি tend ছবির।)

যখন আমরা বিষয়বস্তুগুলি প্রতিস্থাপনের জন্য প্রস্তুত থাকব, আমাদের প্রথমে ফাইলটি কেটে ফেলতে হবে (অন্যথায় যদি আমরা আগে ফাইলের চেয়ে কম বাইট লিখতাম তবে পিছনের বাইটগুলি সেখানেই থাকত)) আমরা কাটা কাটা ব্যবহার করতে পারি (1) সেই উদ্দেশ্যে কোর্টিল থেকে কমান্ড, এবং আমরা এটি আমাদের কাছে থাকা ওপেন ফাইল বর্ণনাকারী ( /dev/fd/3সিউডো-ফাইল ব্যবহার করে ) পাস করতে পারি যাতে এটি ফাইলটি আবার খোলার প্রয়োজন হয় না। (আবার প্রযুক্তিগত দিক থেকে সহজ কিছু : >dir/file.txtসম্ভবত কাজ করবে তবে ফাইলটি পুনরায় খুলতে না পারা এটি আরও মার্জিত সমাধান))


আমি এটি বিবেচনা করেছিলাম, তবে সমস্যাটি হ'ল যদি আমি ফাইলটি তৈরি করার সময় এবং যেখানে আমি এটি লিখতে পারি তার মাঝে অন্য কোনও নির্দোষ ত্রুটি ঘটে থাকে তবে নির্দিষ্ট ফাইলটি ওভাররাইট করা হয়েছে তা জানতে ব্যবহারকারী সম্ভবত বিরক্ত হবে ।
বিওনরোপ

1
@ বাইঅনরোপ অন্য একটি বিকল্প যা ফাইলটি ক্লোবার করবে না তা হ'ল এতে কিছুই যুক্ত করার চেষ্টা করা : echo -n >>fileবা true >> file। অবশ্যই, ext4- এ কেবলমাত্র অতিরিক্ত অ্যাপ্লিকেশন রয়েছে তবে আপনি সেই মিথ্যা পজিটিভ নিয়েই বেঁচে থাকতে পারেন।
মশভী

1
@ বিঅনরোপ আপনার যদি (ক) বিদ্যমান ফাইল বা (খ) নতুন ফাইলটি সংরক্ষণ করার প্রয়োজন হয় তবে এটি আপনার জিজ্ঞাসার চেয়ে আলাদা প্রশ্ন। এর একটি ভাল উত্তর হ'ল নতুন ফাইলটি my-file.txt.backupতৈরি করার আগে বিদ্যমান ফাইলটিকে একটি নতুন নামে (যেমন ) স্থানান্তর করা । অন্য সমাধানটি হ'ল একই ফোল্ডারে অস্থায়ী ফাইলে নতুন ফাইলটি লিখুন, এবং স্ক্রিপ্টের বাকী অংশ সাফল্যের পরে এটি পুরানো ফাইলের উপরে অনুলিপি করুন --- যদি শেষ অপারেশন ব্যর্থ হয়, ব্যবহারকারী নিজেই হারানো ছাড়াই সমস্যাটি সমাধান করতে পারতেন তার বা তার অগ্রগতি।
jpaugh

1
@ বিওনরপ আপনি যদি "পারমাণবিক প্রতিস্থাপন" রুটের জন্য যান (যা একটি ভাল!) তবে সাধারণত আপনি চূড়ান্ত ফাইল হিসাবে একই ডিরেক্টরিতে অস্থায়ী ফাইলটি লিখতে চান (তাদের নাম পরিবর্তনের জন্য একই ফাইল সিস্টেমে থাকতে হবে) (২) সাফল্য অর্জন করতে এবং একটি অনন্য নাম ব্যবহার করুন (সুতরাং স্ক্রিপ্টটি চলার দুটি উদাহরণ থাকলে তারা একে অপরের অস্থায়ী ফাইলগুলিকে আঁকড়ে ধরবে না)) একই ডিরেক্টরিতে লেখার জন্য একটি অস্থায়ী ফাইল খোলাই সাধারণত আপনার পক্ষে একটি ভাল ইঙ্গিত 'পরে এটির পুনরায় নামকরণ করতে সক্ষম হব (ভাল, চূড়ান্ত লক্ষ্য উপস্থিত থাকলে এবং এটি একটি ডিরেক্টরি ডিরেক্টরি বাদে) তবে কিছুটা পরিমাণে এটি আপনার প্রশ্নেরও সমাধান করে।
ফিলাব্রেন্ডেন

1
@ জেপফ - আমি এটি করতে বেশ অনিচ্ছুক। এটি আমার উচ্চ স্তরের সমস্যা সমাধানের চেষ্টা করার সাথে সাথে উত্তরগুলি অনিবার্যভাবে পরিচালিত করবে, যা "আমি কীভাবে চেক করতে পারি ..." এই প্রশ্নের সাথে কোন সম্পর্কযুক্ত সমাধানগুলি স্বীকার করতে পারে। আমার উচ্চ স্তরের সমস্যা যাই হোক না কেন, আমি মনে করি যে এই প্রশ্নটি একা আপনি এমন কিছু হিসাবে দাঁড়িয়েছেন যা আপনি যুক্তিসঙ্গতভাবে করতে চান। যারা এই নির্দিষ্ট প্রশ্নের উত্তর দিচ্ছেন তাদের পক্ষে এটি অন্যায় হবে যদি আমি যদি এটিকে পরিবর্তন করে "আমার স্ক্রিপ্টটির সাথে এই নির্দিষ্ট সমস্যাটি সমাধান করি" to আমি এই বিবরণগুলি এখানে অন্তর্ভুক্ত করেছি কারণ আমাকে জিজ্ঞাসা করা হয়েছিল, তবে আমি প্রাথমিক প্রশ্নটি পরিবর্তন করতে চাই না।
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

আপনি উল্লেখ করেছেন যে ব্যবহারকারীর অভিজ্ঞতা আপনার প্রশ্নটি চালাচ্ছে। আমি একটি ইউএক্স কোণ থেকে উত্তর দেব, যেহেতু আপনি প্রযুক্তিগত দিক থেকে ভাল উত্তর পেয়েছেন।

চেক-আপ-ফ্রন্টটি সম্পাদন করার চেয়ে, কোনও অস্থায়ী ফাইলে ফলাফল লেখার পরে একেবারে শেষে, ব্যবহারকারীর পছন্দসই ফাইলে ফলাফল স্থাপন করা? ভালো লেগেছে:

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

অবশ্যই, তবে এটি ব্যর্থ হতে পারে এমন অনেকগুলি উপায় রয়েছে: ডিস্কটি পূরণ করতে পারে, প্রবাহের ডিরেক্টরিটি মুছে ফেলা যায়, অনুমতিগুলি পরিবর্তন হতে পারে, লক্ষ্য ফাইলটি অন্য কোনও গুরুত্বপূর্ণ সামগ্রীর জন্য ব্যবহার করা যেতে পারে এবং ব্যবহারকারী ভুলে গিয়েছিলেন যে তিনি একই ফাইলটিকে এই দ্বারা নষ্ট করার জন্য নির্ধারিত করেছিলেন অপারেশন. যদি আমরা এটি সম্পর্কে খাঁটি ইউএক্স দৃষ্টিকোণ থেকে কথা বলি, তবে সম্ভবত সঠিক কাজটি হ'ল এটি একটি কাজের জমা দেওয়ার মতো আচরণ করা উচিত: শেষে, যখন আপনি জানেন যে এটি সঠিকভাবে সমাপ্তির জন্য কাজ করেছে, কেবলমাত্র ব্যবহারকারীকে বলুন যে ফলাফল প্রাপ্ত সামগ্রীটি কোথায় থাকে এবং প্রস্তাব দেয় এটি তাদেরকে সরানোর জন্য একটি প্রস্তাবিত আদেশ।
বিশপ

তত্ত্বগতভাবে, হ্যাঁ এখানে অসীম উপায় রয়েছে যা ব্যর্থ হতে পারে। বাস্তবে, এই ব্যর্থতার বেশিরভাগ সময় হ'ল কারণ প্রদত্ত পথটি বৈধ নয়। অপারেশনের মাঝামাঝি সময়ে চাকরি ভাঙার জন্য কিছু দুর্বৃত্ত ব্যবহারকারীকে একযোগে FS সংশোধন করা থেকে আমি যথাযথভাবে আটকাতে পারি না, তবে আমি অবশ্যই অবৈধ বা লিখনযোগ্য পাথের # 1 ব্যর্থতার কারণটি পরীক্ষা করতে পারি।
BeeOnRope

2

টি এল; ডিআর:

: >> "${userfile}"

<> "${userfile}"বা এর বিপরীতে touch "${userfile}", এটি ফাইলের টাইমস্ট্যাম্পগুলিতে কোনও উত্সাহী পরিবর্তন করবে না এবং কেবল লেখার জন্য ফাইলগুলিও কাজ করবে।


ওপি থেকে:

ফাইলটি তৈরি / ওভাররাইট করা যায়, তবে আসলে এটি তৈরি করা যায় না কিনা আমি যুক্তিসঙ্গত চেক করতে চাই।

এবং আপনার মন্তব্য থেকে আমার উত্তরের উত্তর ইউএক্স দৃষ্টিকোণ থেকে :

এই ব্যর্থতার বেশিরভাগ সময় হ'ল কারণ প্রদত্ত পথটি বৈধ নয়। অপারেশনের মাঝামাঝি সময়ে চাকরি ভাঙার জন্য আমি কিছু দুর্বৃত্ত ব্যবহারকারী একযোগে এফএস সংশোধন করতে পারি না, তবে আমি অবশ্যই অবৈধ বা লিখনযোগ্য পথের # 1 ব্যর্থতার কারণটি পরীক্ষা করতে পারি।

একমাত্র নির্ভরযোগ্য পরীক্ষা open(2)ফাইলটির, কারণ কেবল এটিই লেখার যোগ্যতা সম্পর্কে প্রতিটি প্রশ্নের সমাধান করে: পথ, মালিকানা, ফাইল সিস্টেম, নেটওয়ার্ক, সুরক্ষা প্রসঙ্গ ইত্যাদি Any অন্য কোনও পরীক্ষা লিখনের কিছু অংশকে সম্বোধন করবে তবে অন্য নয়। আপনি যদি পরীক্ষাগুলির একটি উপসেট চান, তবে শেষ পর্যন্ত আপনার জন্য গুরুত্বপূর্ণ কী তা চয়ন করতে হবে।

তবে এখানে আরেকটি চিন্তাভাবনা রয়েছে। আমি যা বুঝতে পারি তা থেকে:

  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

আমি যখন দাবি করছি (আমার অন্য উত্তরে) যে সর্বাধিক ব্যবহারকারীর-বন্ধুত্বপূর্ণ পদ্ধতির মধ্যে ব্যবহারকারীকে স্থানান্তর করতে হবে এমন একটি অস্থায়ী ফাইল তৈরি করা হয়, তবে আমি মনে করি যে তাদের ইনপুটটি পুরোপুরি পর্যবেক্ষণ করার জন্য এটি সর্বনিম্ন ব্যবহারকারী-বৈরী approach

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.