আইএফ এর ভিতরে যখন ব্যাচ ফাইলের ভেরিয়েবল সেট করা হচ্ছে না?


69

আমার কাছে খুব সাধারণ ব্যাচের ফাইলগুলির দুটি উদাহরণ রয়েছে:

একটি ভেরিয়েবলের জন্য একটি মান নির্ধারণ করা:

@echo off
set FOO=1
echo FOO: %FOO%
pause
echo on

যা প্রত্যাশিত হিসাবে ফলাফল:

FOO: 1 
Press any key to continue . . .

যাইহোক, যদি আমি একই দুটি লাইনটি যদি কোনও সংজ্ঞায়িত ব্লকের মধ্যে রাখি:

@echo off
IF NOT DEFINED BAR (
    set FOO=1
    echo FOO: %FOO%
)
pause
echo on

এটি অপ্রত্যাশিতভাবে ফলাফল:

FOO: 
Press any key to continue . . .

এই করা উচিত নয় যদি স্পষ্ট ব্লক মৃত্যুদন্ড কার্যকর করা হচ্ছে সাথে কিছু আছে। আমি যদি উপরের বারটিকে সংজ্ঞায়িত করি তবে কেবল PAUSE কমান্ডের পাঠ্য প্রত্যাশিতভাবে প্রদর্শিত হবে।

কি দেয়?


প্রশ্ন অনুসরণ করুন: সেটলোকাল ছাড়া বিলম্বিত প্রসারণ সক্ষম করার কোনও উপায় আছে কি?

যদি আমি এই সাধারণ উদাহরণটিকে ব্যাচের ফাইলটিকে অন্য একজনের কাছ থেকে কল করতে পারি তবে উদাহরণটি FOO সেট করে তবে কেবল স্থানীয়।

উদাহরণ স্বরূপ:

testcaller.bat

@call test.bat 
@echo FOO: %FOO% 
@pause 

test.bat

@setlocal EnableDelayedExpansion 
@IF NOT DEFINED BAR ( 
    @set FOO=1 
    @echo FOO: !FOO! 
) 

এটি প্রদর্শন করে:

FOO: 1 
FOO: 
Press any key to continue . . . 

এই ক্ষেত্রে, এটি প্রদর্শিত হচ্ছে যে আমি কলার মধ্যে বিলম্বিত প্রসারণ সক্ষম করতে হবে, যা ঝামেলা হতে পারে।

উত্তর:


84

যখন একটি লাইন পার্স করা হয় তখন ব্যাচ ফাইলে পরিবেশগত ভেরিয়েবলগুলি প্রসারিত হয়। প্রথম বন্ধনী (আপনার হিসাবে if defined) দ্বারা সীমাবদ্ধ ব্লকের ক্ষেত্রে পুরো ব্লকটি একটি "লাইন" বা কমান্ড হিসাবে গণনা করে।

এর অর্থ হ'ল% FOO% এর সমস্ত উপস্থিতি ব্লক চালানোর আগে তাদের মান দ্বারা প্রতিস্থাপন করা হয় । আপনার ক্ষেত্রে কিছুই না থাকায় ভেরিয়েবলের এখনও কোনও মূল্য নেই।

এটি সমাধানের জন্য আপনি বিলম্বিত প্রসারণ সক্ষম করতে পারবেন :

setlocal enabledelayedexpansion

বিলম্বিত প্রসারণের কারণে বিস্ময়কর চিহ্নগুলি ( !) দ্বারা পার্সিংয়ের পরিবর্তে মৃত্যুদণ্ড কার্যকর করা যায় যা আপনার ক্ষেত্রে সঠিক আচরণ নিশ্চিত করবে:

if not defined BAR (
    set FOO=1
    echo Foo: !FOO!
)

help set এটিও বিশদ:

অবশেষে, বিলম্বিত পরিবেশের পরিবর্তনশীল প্রসারণের জন্য সমর্থন যুক্ত করা হয়েছে। এই সমর্থনটি সর্বদা ডিফল্টরূপে অক্ষম থাকে তবে /Vকমান্ড লাইনটি স্যুইচ-এ সক্রিয় / অক্ষম থাকতে পারে CMD.EXE। দেখাCMD /?

বিলম্বিত পরিবেশের পরিবর্তনশীল প্রসারণ বর্তমান প্রসারণের সীমাবদ্ধতাগুলি ঘুরে দেখার জন্য দরকারী যা পাঠের একটি লাইন পড়ার সময় ঘটে না যখন কার্যকর হয় happens নিম্নলিখিত উদাহরণটি তাত্ক্ষণিক পরিবর্তনশীল প্রসারণ সহ সমস্যাটি দেখায়:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

বার্তা প্রদর্শন না হবে, যেহেতু %VAR%উভয় IF বিবৃতি, যখন প্রথম If Statement পড়া হয় প্রতিস্থাপিত, যেহেতু এটি কথাটি লাশ রয়েছে IF, যা একটি যৌগ বিবৃতি হল। সুতরাং যৌগিক বিবৃতিটির ভিতরে থাকা আইএফ সত্যই "পূর্বে" সাথে "পরে" তুলনা করছে যা কখনই সমান হবে না। একইভাবে, নিম্নলিখিত উদাহরণটি প্রত্যাশার মতো কাজ করবে না:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

এটি বর্তমান ডিরেক্টরিতে ফাইলগুলির একটি তালিকা তৈরি করবে না , তবে পরিবর্তে এটি কেবলমাত্র LIST পাওয়া শেষ ফাইলটিতে ভেরিয়েবল সেট করবে । আবার এটি কারণ কারণ বিবৃতিটি পড়ার %LIST%পরে একবারটি প্রসারিত FORহয় এবং সেই সময় LISTভেরিয়েবলটি খালি থাকে। সুতরাং আসল ফর লুপটি আমরা কার্যকর করছি:

for %i in (*) do set LIST= %i

যা সবেমাত্র LISTশেষ ফাইলটিতে সেট করে রাখে ।

বিলম্বিত পরিবেশের পরিবর্তনশীল প্রসার আপনাকে কার্যকরকরণের সময় পরিবেশের ভেরিয়েবলগুলি প্রসারণ করতে একটি পৃথক অক্ষর (বিস্মৃতি চিহ্ন) ব্যবহার করতে দেয়। যদি বিলম্বিত ভেরিয়েবল প্রসারণ সক্ষম করা হয় তবে উপরোক্ত উদাহরণগুলি উদ্দেশ্য হিসাবে কাজ করার জন্য নিম্নলিখিত হিসাবে রচনা করা যেতে পারে:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "!VAR!" == "after" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%

17
এবং যদি আপনার প্রতিধ্বনি করতে হয় তবে !ব্যবহার করুন ^^^!(এটি দুটিবার পালিয়ে যান)। অন্যথায় "বিলম্বিত সম্প্রসারণ" বৈশিষ্ট্যটি এটি খাবে।
মহাকর্ষ

4

কমান্ডগুলি যখন একক লাইনে থাকে ( &কমান্ড বিভাজক): একই আচরণটি ঘটে তখন :

if not defined BAR set FOO=1& echo FOO: %FOO%

জোয়ের ব্যাখ্যাটি আমার প্রিয়। তবে নোট enabledelayedexpansionকরুন যা উইন্ডোজ এনটি 4.0 এ কাজ করে না (এবং আমি উইন্ডোজ 2000 সম্পর্কে নিশ্চিত নই)।

আপনার ফলোআপ প্রশ্ন সম্পর্কে, না, এটি EnableDelayedExpansionছাড়া সম্ভব নয় setlocal। তবে আপনার বিরুদ্ধে যে আসল আচরণটি চলছিল সেটি দ্বিতীয়বারের মতো চাপের জন্য ব্যবহার করা যেতে পারে: কৌশলটি হ'ল endlocalএকই লাইনে যেখানে আপনি প্রয়োজনীয় ভেরিয়েবলগুলির মানগুলি আবার সেট করেছেন।

এখানে আপনার test.batসংশোধিত:

@echo off
setlocal EnableDelayedExpansion 
IF NOT DEFINED BAR ( 
    set FOO=1 
    echo FOO: !FOO! 
)
endlocal & set FOO=%FOO%

তবে সেই সমস্যাটির জন্য আরও কাজ করতে হবে: একটি ইনলাইন ব্লক বা বাহ্যিক ফাইলের পরিবর্তে একই ফাইলে একটি পদ্ধতি ব্যবহার করুন।

@echo off
if not defined BAR call :NotDefined
pause
goto :EOF

:NotDefined
set FOO=1
echo FOO: %FOO%
goto :EOF

"কৌশলটি একই লাইনে এন্ডলোকাল করা" - এর জন্য ধন্যবাদ!
ডিফল্ট করুন

3

যদি এটি সেভাবে কাজ করে না, আপনি সম্ভবত পরিবেশের পরিবর্তনশীল প্রসারণটি বিলম্ব করেছেন। আপনি হয় এটি দিয়ে বন্ধ করতে পারেন cmd /V:OFFবা আপনার ভিতরে উদ্দীপনা চিহ্নগুলি ব্যবহার করতে পারেন যদি:

@echo off
IF NOT DEFINED BAR (
    set FOO=1
    echo FOO: !FOO!
)
pause
echo on

3
বিলম্বিত সম্প্রসারণ সক্ষম করা কেবলমাত্র বিস্মৃত চিহ্নের শব্দার্থকে পরিবর্তিত করে। এটি স্বাভাবিক পরিবর্তনশীল প্রসারণের উপর কোনও প্রভাব ফেলবে না। তদাতিরিক্ত, দুর্ঘটনাক্রমে এটি সক্ষম করা খুব সম্ভব নয়; যে ব্যক্তিরা এটি সক্ষম করেছে তারা সাধারণত উদ্দেশ্য অনুযায়ী করে।
জোয়

1

এটি ঘটে কারণ আপনার FORকমান্ড সহ লাইনটি একবারে মূল্যায়ন করে। এটি পুনর্বিবেচনা করার জন্য আপনার কিছু উপায় দরকার। আপনি CALLকমান্ডের সাহায্যে বিলম্বিত সম্প্রসারণ অনুকরণ করতে পারেন :

for /l %%I in (0,1,5) do call echo %%RANDOM%%

বিলম্বিত সম্প্রসারণটি কাজ করে নি, তবে উইন 7-এ এই কল / কাজ করেছে, আমার 3 লাইন সেন্টিমিডি স্ক্রিপ্টটির জন্য আসল হার্ডলিঙ্কটি খুঁজে পেতে: @ for / f "delims =" %% a in ('bash ~ / perl / cwd2 .শ% * ') কল সেট করুন সিডব্লুড্লাল = %% একটি প্রতিধ্বনি সিডি / ডি% সিডব্লিউডি_REAL% সিডি / ডি% সিডাব্লুডি%
মোশ

0

এটি লক্ষ করার মতো যে এটি যদি একই লাইনে একক কমান্ড দেয় তবে এটি কাজ করে।

যেমন

   if not defined BAR set FOO=1

আসলে FOO1 এ সেট করা হবে আপনি এর পরে অন্য চেক যেমন করতে পারেন:

   if not defined BAR echo FOO: %FOO%

আরে, আমি কখনও বলিনি এটি সুন্দর ছিল। তবে আপনি যদি সেটলোকাল বা বিলম্বিত সম্প্রসারণ ব্যবসায়ের সাথে ঝামেলা করতে না চান তবে এটি একটি দ্রুত কাজ।


0

কখনও কখনও, যেমনটি আমার ক্ষেত্রে ছিল, যখন আপনাকে পুরানো এনটি 4 সার্ভারের মতো লেগ্যাসি সিস্টেমগুলির সাথে সামঞ্জস্য করা দরকার যেখানে বিলম্বিত সম্প্রসারণ কাজ করছে না বা কোনও কারণে কাজ করছে না আপনাকে বিকল্প সমাধানের প্রয়োজন হতে পারে।

আপনি বিলম্বিত প্রসারণটি ব্যবহার করবেন এমন ক্ষেত্রেও সুপারিশ করেছিলেন যে ব্যাচের অন্তত চেক অন্তর্ভুক্ত করা উচিত:

IF NOT %Comspec%==!Comspec! ECHO Delayed Expansion is NOT enabled. 

আপনি যদি কেবল আরও পাঠযোগ্য এবং সহজ পদ্ধতির চান, তবে এখানে বিকল্প সমাধান রয়েছে:

REM Option 2: use `call` inside block statement
IF NOT DEFINED BAR2 ( 
  set FOO2=2 
  call echo FOO2: %%FOO2%%
)
echo FOO2: %FOO2%

যা এর মতো কাজ করে:

>REM Option 2: use `call` inside block statement

>IF NOT DEFINED BAR2 (
 set FOO2=2
 call echo FOO2: %FOO2%
)
FOO2: 2

>echo FOO2: 2
FOO2: 2

এবং আরও একটি খাঁটি সেমিডি সমাধান:

REM Option 3: use `goto` logic blocks
IF DEFINED BAR3 goto endbar3
  set FOO3=3 
  echo FOO3: %FOO3%
:endbar3
echo FOO3: %FOO3%

এটি এর মতো কাজ করে:

>REM Option 3: use `goto` logic blocks

>IF DEFINED BAR3 goto endbar3

>set FOO3=3

>echo FOO3: 3
FOO3: 3

>echo FOO3: 3
FOO3: 3

এবং এটি সম্পূর্ণ যদি পূর্ণ এলিট সিনট্যাক্স সমাধান:

REM Full IF THEN ELSE solution
IF NOT DEFINED BAR4 goto elsebar4
REM this is TRUE condition, normal batch flow
  set FOO4=6
  echo FOO4: %FOO4%
  goto endbar4
:elsebar4
  set FOO4=4
  echo FOO4: %FOO4%
  set BAR4=4
:endbar4
echo FOO4: %FOO4%
echo BAR4: %BAR4%

এটি এর মতো কাজ করে:

>REM Full IF THEN ELSE solution

>IF NOT DEFINED BAR4 goto elsebar4

>set FOO4=4

>echo FOO4: 4
FOO4: 4

>set BAR4=4

>echo FOO4: 4
FOO4: 4

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