পুরো শেল স্ক্রিপ্টটি কার্যকর করার আগে কীভাবে পড়বেন?


35

সাধারণত, আপনি যদি কোনও স্ক্রিপ্ট সম্পাদনা করেন তবে স্ক্রিপ্টের সমস্ত চলমান ব্যবহার ত্রুটিযুক্ত।

যতদূর আমি এটি বুঝতে পারি, বাশ (অন্যান্য শেলগুলিও?) স্ক্রিপ্টটি ক্রমবর্ধমানভাবে পড়ুন, সুতরাং আপনি যদি স্ক্রিপ্ট ফাইলটি বাহ্যিকভাবে সংশোধন করেন তবে এটি ভুল জিনিসগুলি পড়া শুরু করে। এটি রোধ করার কোনও উপায় আছে কি?

উদাহরণ:

sleep 20

echo test

আপনি যদি এই স্ক্রিপ্টটি কার্যকর করেন, বাশ প্রথম লাইনটি পড়বে (10 বাইট বলুন) এবং ঘুমাতে যাবে। যখন এটি পুনরায় শুরু হয়, স্ক্রিপ্টে 10 তম বাইট থেকে শুরু করে বিভিন্ন সামগ্রী থাকতে পারে। আমি নতুন স্ক্রিপ্টের একটি লাইনের মাঝে থাকতে পারি। এভাবে চলমান স্ক্রিপ্টটি নষ্ট হয়ে যাবে।


"স্ক্রিপ্টটি বাহ্যিকভাবে সংশোধন" বলতে আপনার অর্থ কী?
মোলিংলাভস

1
হয়ত কোনও ফাংশন বা কিছুতে সমস্ত বিষয়বস্তু মোড়ানোর কোনও উপায় আছে, তাই শেলটি পুরো লিপিটি প্রথমে পড়বে? তবে আপনি যেখানে শেষ লাইনটি ফাংশনটি চালু করবেন সে সম্পর্কে কী এটি ইওএফ পর্যন্ত পড়া হবে? শেষটা বাদ দিয়ে \nকি কৌতুক করবে? হয়তো সাবসেল ()করবে? আমি এটির সাথে খুব অভিজ্ঞ নই, দয়া করে সহায়তা করুন!
ভাস্যনাভিকভ

@ মলিউডিংস যদি স্ক্রিপ্টের মতো সামগ্রী থাকে sleep 20 ;\n echo test ;\n sleep 20এবং আমি এটি সম্পাদনা শুরু করি তবে এটি খারাপ ব্যবহার করতে পারে। উদাহরণস্বরূপ, বাশ স্ক্রিপ্টের প্রথম 10 বাইট পড়তে পারে, sleepআদেশটি বুঝতে পারে এবং ঘুমাতে যেতে পারে। এটি পুনরায় শুরু হওয়ার পরে, ফাইলটিতে 10 বাইট থেকে শুরু করে বিভিন্ন সামগ্রী থাকবে।
ভাস্যনাভিকভ

1
সুতরাং, আপনি যা বলছেন তা হ'ল আপনি যে কোনও স্ক্রিপ্ট সম্পাদন করছেন যা সম্পাদন করছে? প্রথমে স্ক্রিপ্টটি থামান, আপনার সম্পাদনাগুলি করুন এবং তারপরে এটি আবার শুরু করুন।
মোলিংলাভ

@ মলিউডিংস হ্যাঁ, এটি মূলত এটি। সমস্যাটি হচ্ছে, স্ক্রিপ্টগুলি বন্ধ করা আমার পক্ষে সুবিধাজনক নয় এবং এটি করা সর্বদা মনে রাখা খুব কঠিন hard প্রথমে পুরো স্ক্রিপ্টটি পড়ার জন্য বাশকে বাধ্য করার কোনও উপায় আছে?
ভাস্যনাভিকভ

উত্তর:


43

হ্যাঁ শেলস এবং bashবিশেষত, ফাইলগুলি একবারে এক লাইনে পড়তে সতর্ক থাকে, তাই এটি আপনি যখন ইন্টারেক্টিভভাবে ব্যবহার করেন তখন একই কাজ করে।

আপনি লক্ষ্য করবেন যে ফাইলটি যখন (যেমন পাইপের মতো) সন্ধানযোগ্য না হয়, bashএমনকি \nঅক্ষরটি অতীতটি না পড়ে তা নিশ্চিত হওয়ার জন্য এমনকি একবারে একটি বাইটও পড়ে । ফাইলটি সন্ধানযোগ্য হলে এটি একবারে সম্পূর্ণ ব্লকগুলি পড়ে উপযুক্ত করে তবে এর পরে ফিরে যেতে চেষ্টা করে \n

এর অর্থ আপনি এই জাতীয় জিনিসগুলি করতে পারেন:

bash << \EOF
read var
var's content
echo "$var"
EOF

অথবা স্ক্রিপ্টগুলি লিখুন যা নিজেরাই আপডেট করে। যা আপনাকে যদি গ্যারান্টি দেয় না তবে আপনি তা করতে সক্ষম হবেন না।

এখন, এটি বিরল যে আপনি things জাতীয় জিনিসগুলি করতে চান এবং যেমনটি আপনি খুঁজে পেয়েছেন যে বৈশিষ্ট্যটি দরকারী হিসাবে এটি প্রায়শই প্রায় পেতে চলেছে।

এটি এড়ানোর জন্য, আপনি চেষ্টা করে নিশ্চিত করতে পারেন যে আপনি জায়গাটিতে ফাইলটি সংশোধন করছেন না (উদাহরণস্বরূপ, একটি অনুলিপি সংশোধন করুন এবং অনুলিপিটি জায়গায় স্থানান্তরিত করুন (যেমন sed -iবা perl -piকিছু সম্পাদক যেমন উদাহরণস্বরূপ করেন))।

অথবা আপনি আপনার স্ক্রিপ্টটি লিখতে পারেন:

{
  sleep 20
  echo test
}; exit

(দ্রষ্টব্য যে এটি exitএকই লাইনে থাকা গুরুত্বপূর্ণ }; যদিও আপনি এটি বন্ধনীটির ঠিক আগে এটি বন্ধনীগুলির মধ্যে রাখতে পারেন)।

বা:

main() {
  sleep 20
  echo test
}
main "$@"; exit

শেলটির exitকোনও কিছু শুরু করার আগে পর্যন্ত স্ক্রিপ্টটি পড়া দরকার । এটি নিশ্চিত করে যে শেলটি আবার স্ক্রিপ্ট থেকে পড়বে না।

এর অর্থ যদিও পুরো স্ক্রিপ্টটি মেমোরিতে সংরক্ষণ করা হবে।

এটি স্ক্রিপ্টের বিশ্লেষণকেও প্রভাবিত করতে পারে।

উদাহরণস্বরূপ, এতে bash:

export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'

UTF-8 এ এনকোড করা U + 00E9 আউটপুট দেয়। তবে আপনি যদি এটিকে পরিবর্তন করেন:

{
  export LC_ALL=fr_FR.UTF-8
  echo $'St\ue9phane'
}

\ue9অক্ষরসেট যে সময়ে কার্যকর ছিল যে কমান্ড পার্স করা হয় এই ক্ষেত্রে হয় যা সম্প্রসারিত হবে আগেexport কমান্ড মৃত্যুদন্ড কার্যকর করা হয়।

আরও মনে রাখবেন যে যদি কয়েকটি শাঁস সহ যদি sourceআর্ফ .আদেশটি ব্যবহৃত হয় তবে আপনার উত্সযুক্ত ফাইলগুলির জন্য একই ধরণের সমস্যা হবে problem

যে ক্ষেত্রে নয় এর bashযার যদিও sourceকমান্ড এটা ব্যাখ্যা করার আগে সম্পূর্ণরূপে ফাইল পড়া হয়। bashবিশেষভাবে লিখতে থাকলে , আপনি স্ক্রিপ্টের শুরুতে যুক্ত করে বাস্তবে এটি ব্যবহার করতে পারেন:

if [[ ! $already_sourced ]]; then
  already_sourced=1
  source "$0"; exit
fi

(আমি এটির উপর নির্ভর করব না যদিও আপনি ভবিষ্যতের সংস্করণগুলি bashএমন আচরণটি পরিবর্তন করতে পারবেন যা বর্তমানে সীমাবদ্ধতা হিসাবে দেখা যেতে পারে (ব্যাশ এবং এটিএন্ডটি টিএসএইচএস কেবল পসিক্সের মতো শেল যা যতদূর বলতে পারে) এবং already_sourcedকৌশলটি কিছুটা ভঙ্গুর কারণ এটি ধরে নিয়েছে যে ভেরিয়েবল পরিবেশে নেই, এটি BASH_SOURCE ভেরিয়েবলের সামগ্রীকে প্রভাবিত করে তা উল্লেখ করার প্রয়োজন নেই)


@ ভাস্যনাভিকভ, এসই-তে এই মুহূর্তে (বা কমপক্ষে আমার জন্য) কিছু ভুল হয়েছে বলে মনে হচ্ছে। আমি আমার যোগ করার সময় কেবলমাত্র দুটি উত্তর ছিল, এবং আপনার মন্তব্যটি এখন কেবল আপ হয়েছে বলে মনে হচ্ছে এটি 16 মিনিট আগে পোস্ট করা হয়েছিল (বা এটি সম্ভবত আমার মার্বেলগুলি হারাতে পারে)) যাইহোক, ফাইলের আকার বাড়লে সমস্যাগুলি এড়াতে এখানে প্রয়োজনীয় অতিরিক্ত "প্রস্থান" নোট করুন (আমি আপনার উত্তরে মন্তব্যটিতে যুক্ত করেছি)
স্টাফেন চেজেলাস

স্টাফেন, আমি মনে করি আমি আরও একটি সমাধান খুঁজে পেয়েছি। এটি ব্যবহার করা হয় }; exec true। এইভাবে, ফাইলের শেষে নিউলাইনগুলিতে কোনও প্রয়োজন নেই যা কিছু সম্পাদকের (যেমন ইমাসের মতো) বন্ধুত্বপূর্ণ। সমস্ত পরীক্ষাগুলি যা আমি সঠিকভাবে কাজের সাথে ভাবতে পারি}; exec true
ভাস্যনাভিকভ

@ ভাস্যনাভিকভ, আপনার অর্থ কী তা নিশ্চিত হন না। এর চেয়ে ভাল কেমন }; exit? আপনি প্রস্থান স্থিতি হারাচ্ছেন।
স্টাফেন চেজেলাস

ভিন্ন প্রশ্নে যেমন উল্লেখ করা হয়েছে: ডট কমান্ড ( . script) ব্যবহারের ক্ষেত্রে প্রথমে পুরো ফাইলটি পার্স করা এবং তারপরে যৌগিক বিবৃতি কার্যকর করা সাধারণ ।
সহজেই

@ দক্ষতার সাথে, হ্যাঁ আমি এই উত্তরে এটিএন্ডটি টিএসএস এবং ব্যাশের সীমাবদ্ধতা হিসাবে উল্লেখ করেছি। অন্যান্য পসিক্স-ধরণের শেলের মধ্যে এই সীমাবদ্ধতা নেই।
স্টাফেন চেজেলাস

12

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

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


"মুছুন" আসলে প্রক্রিয়াটির অংশ নয়। আপনি যদি এটি যথাযথভাবে পারমাণবিক করতে চান তবে আপনি গন্তব্য ফাইলটির উপর একটি নতুন নামকরণ করুন - আপনার যদি মুছে ফেলার পদক্ষেপ থাকে, আপনার প্রক্রিয়াটি মুছে ফেলার পরে মারা যায় তবে পুনরায় নামকরণের আগে, কোনও ফাইলই জায়গায় রাখবেন না ( বা পাঠক সেই উইন্ডোটিতে ফাইলটি অ্যাক্সেস করার চেষ্টা করুন এবং পুরানো বা নতুন সংস্করণ পাওয়া যায় না)।
চার্লস ডাফি

11

সহজ সমাধান:

{
  ... your code ...

  exit
}

এইভাবে, বাশ {}এটি সম্পাদন করার আগে পুরো ব্লকটি পড়বে এবং exitনির্দেশিকাটি কোড ব্লকের বাইরে কোনও কিছু পড়বে না তা নিশ্চিত করবে।

আপনি যদি স্ক্রিপ্টটি "চালনা" করতে না চান, বরং এটি "উত্স" করতে চান তবে আপনার আলাদা সমাধান দরকার। এটি তখন কাজ করা উচিত:

{
  ... your code ...

  return 2>/dev/null || exit
}

অথবা আপনি যদি প্রস্থান কোডের উপর সরাসরি নিয়ন্ত্রণ চান:

{
  ... your code ...

  ret="$?";return "$ret" 2>/dev/null || exit "$ret"
}

ভাল খবর! এই স্ক্রিপ্টটি সম্পাদনা, উত্স এবং সম্পাদন করা নিরাপদ। আপনাকে এখনও নিশ্চিত হতে হবে যে প্রাথমিকভাবে এটি পড়ার সময় আপনি সেই মিলিসেকেন্ডগুলিতে এটি সংশোধন করবেন না।


1
আমি যা খুঁজে পেয়েছি তা হল এটি ইওএফটি দেখতে পায় না এবং ফাইলটি পড়া বন্ধ করে দেয় না তবে এটি তার "বাফার স্ট্রিম" প্রক্রিয়াকরণে জড়িয়ে পড়ে এবং ফাইলটির শেষের দিকে খোঁজ করে শেষ হয়, যার কারণ এটি আকারের আকারের মতো দেখায় ঠিক আছে ফাইলটি আগের চেয়ে দ্বিগুণের চেয়ে বেশি ফাইল তৈরি করলে ফাইলটি খুব বেশি বেড়ে যায় না, তবে খারাপ লাগে। আমি খুব শীঘ্রই ব্যাশ রক্ষণাবেক্ষণকারীদের কাছে একটি বাগ রিপোর্ট করব।
স্টাফেন চেজেলাস


মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
টেরডন

5

ধারণার প্রমাণ. এখানে একটি স্ক্রিপ্ট যা নিজেই পরিবর্তন করে:

cat <<EOF >/tmp/scr
#!/bin/bash
sed  s/[k]ept/changed/  /tmp/scr > /tmp/scr2

# this next line overwites the on disk copy of the script
cat /tmp/scr2 > /tmp/scr
# this line ends up changed.
echo script content kept
EOF
chmod u+x /tmp/scr
/tmp/scr

আমরা পরিবর্তিত সংস্করণ মুদ্রণ দেখতে পাচ্ছি

এটি কারণ হ'ল বাশ লোডগুলি স্ক্রিপ্টে খোলার জন্য একটি ফাইল হ্যান্ডেল রাখে, তাই ফাইলটিতে পরিবর্তনগুলি অবিলম্বে দেখা যাবে will

আপনি যদি ইন-মেমরি অনুলিপিটি আপডেট করতে না চান তবে মূল ফাইলটিকে লিঙ্ক করুন এবং এটি প্রতিস্থাপন করুন।

এটির একটি উপায় সেড -i ব্যবহার করে।

sed -i '' filename

ধারণার প্রমাণ

cat <<EOF >/tmp/scr
#!/bin/bash
sed  s/[k]ept/changed/  /tmp/scr > /tmp/scr2

# this next line unlinks the original and creates a new copy.
sed -i ''  /tmp/scr

# now overwriting it has no immediate effect
cat /tmp/scr2 > /tmp/scr
echo script content kept
EOF

chmod u+x /tmp/scr
/tmp/scr

আপনি যদি স্ক্রিপ্টটি পরিবর্তন করতে কোনও সম্পাদক ব্যবহার করছেন, "ব্যাকআপ কপি রাখুন" বৈশিষ্ট্যটি সক্ষম করা কেবলমাত্র বিদ্যমান একটি ওভাররাইট না করে সম্পাদকের পরিবর্তিত সংস্করণটিকে একটি নতুন ফাইলে লেখার প্রয়োজন হতে পারে।


2
না, bashদিয়ে ফাইলটি খোলেন না mmap()। এটি প্রয়োজন অনুযায়ী একবারে একটি লাইন পড়তে কেবল সতর্কতা অবলম্বন করে ঠিক যেমন ইন্টারেক্টিভ করার সময় টার্মিনাল ডিভাইস থেকে আদেশ প্রাপ্ত হয়।
স্টাফেন চেজেলাস

2

আপনার স্ক্রিপ্টটিকে কোনও ব্লকে মোড়ানো {}সম্ভবত সেরা বিকল্প তবে আপনার স্ক্রিপ্টগুলি পরিবর্তন করা দরকার।

F=$(mktemp) && cp test.sh $F && bash $F; rm $F;

দ্বিতীয় সেরা বিকল্প হবে (ধরে নেওয়া tmpfs ) অসুবিধাটি হ'ল যদি আপনার স্ক্রিপ্টগুলি এটি ব্যবহার করে তবে এটি $ 0 টি ব্রেক করে।

এর মতো কিছু ব্যবহার F=test.sh; tail -n $(cat "$F" | wc -l) "$F" | bashকরা কম আদর্শ কারণ এটি পুরো ফাইলটিকে মেমোরিতে রাখতে হয় এবং $ 0 ব্রেক করে।

মূল ফাইলটি স্পর্শ করা এড়ানো উচিত যাতে সর্বশেষ সংশোধিত সময়, লক পড়ুন এবং হার্ড লিঙ্কগুলি বিরক্ত না হয়। এই ভাবে আপনি ফাইলটি চালনার সময় সম্পাদককে খোলা রাখতে পারবেন এবং আরএসসিএনএস অপ্রয়োজনীয়ভাবে প্রত্যাশার মতো ব্যাকআপ এবং হার্ড লিঙ্ক ফাংশনের জন্য ফাইলটি চেকসাম করবে না।

সম্পাদনা ফাইলটি প্রতিস্থাপন কাজ করবে কিন্তু কম শক্তিশালী কারণ এটি অন্যান্য স্ক্রিপ্ট / ব্যবহারকারীদের জন্য প্রয়োগযোগ্য নয় / অথবা কেউ ভুলে যেতে পারে। এবং আবার এটি শক্ত লিঙ্কগুলি ভঙ্গ করবে।


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