খালি তালিকায় ফোরচ লুপ সুরক্ষিত করুন


10

পাওয়ারশেল ভি 2.0 ব্যবহার করে আমি এক্স দিনের চেয়ে পুরানো যে কোনও ফাইল মুছতে চাই:

$backups = Get-ChildItem -Path $Backuppath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like "backup*")}

foreach ($file in $backups)
{
    Remove-Item $file.FullName;
}

তবে, যখন $ ব্যাকআপগুলি খালি থাকে আমি পাই: Remove-Item : Cannot bind argument to parameter 'Path' because it is null.

আমি চেষ্টা করেছিলাম:

  1. সঙ্গে foreach রক্ষা if (!$backups)
  2. এর সাথে সরান-আইটেমটি রক্ষা করা হচ্ছে if (Test-Path $file -PathType Leaf)
  3. এর সাথে সরান-আইটেমটি রক্ষা করা হচ্ছে if ([IO.File]::Exists($file.FullName) -ne $true)

এগুলির কোনওটিই কাজ করছে বলে মনে হয় না, যদি তালিকাটি খালি থাকে তবে কোনও ফোরচ লুপ প্রবেশের প্রতিরোধের প্রস্তাবিত উপায় যদি হয়?


@ ড্যান - উভয় চেষ্টা করে ($ ব্যাকআপ> 0) এবং (@ ($ ব্যাকআপগুলি) c গণনা -gt 0), তবে ফাইল নেই যখনই প্রত্যাশিতভাবে কাজ করে না।
স্টিবি

উত্তর:


19

পাওয়ারশেল 3 দিয়ে foreachবিবৃতিটি পুনরাবৃত্তি হয় না $nullএবং ওপি দ্বারা বর্ণিত সমস্যাটি আর ঘটে না।

থেকে উইন্ডোজ PowerShell ব্লগ পোস্টে নতুন V3 ভাষা বৈশিষ্ট্য :

ForEach স্টেটমেন্ট $ n নাল দিয়ে পুনরাবৃত্তি করে না

পাওয়ারশেল ভি 2.0-তে লোকেরা প্রায়শই অবাক হত:

PS> foreach ($i in $null) { 'got here' }

got here

এই পরিস্থিতি প্রায়শই দেখা দেয় যখন কোনও সেন্টিমলেট কোনও বস্তু ফেরত দেয় না। পাওয়ারশেল ভি ৩.০-তে, $ n নাল দিয়ে পুনরাবৃত্তি এড়াতে আপনার যদি একটি বিবৃতি যুক্ত করতে হবে না। আমরা আপনার জন্য এটি যত্ন নিতে।

পাওয়ারশেলের $PSVersionTable.PSVersion.Major -le 2জন্য মূল উত্তরের জন্য নিম্নলিখিতটি দেখুন।


আপনার দুটি বিকল্প আছে, আমি বেশিরভাগই দ্বিতীয়টি ব্যবহার করি।

$backupsনা পরীক্ষা করুন $nullIfলুপের চারপাশে একটি সহজ এটি পরীক্ষা করতে পারে$null

if ( $backups -ne $null ) {

    foreach ($file in $backups) {
        Remove-Item $file.FullName;
    }

}

অথবা

$backupsনাল অ্যারে হিসাবে আরম্ভ করুন । এটি আপনার শেষ প্রশ্নে জিজ্ঞাসা করা "পুনরাবৃত্তি খালি অ্যারে" ইস্যুটির অস্পষ্টতা এড়ায় ।

$backups = @()
# $backups is now a null value array

foreach ( $file in $backups ) {
    # this is not reached.
    Remove-Item $file.FullName
}

দুঃখিত, আমি আপনার কোড সংহত করার একটি উদাহরণ প্রদান করতে অবহেলা করেছি। Get-ChildItemঅ্যারেতে মোড়ানো সেমিডলেট নোট করুন । এটি এমন ফাংশনগুলির সাথেও কাজ করবে যা একটি ফিরে আসতে পারে $null

$backups = @(
    Get-ChildItem -Path $Backuppath |
        Where-Object { ($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like "backup*") }
)

foreach ($file in $backups) {
    Remove-Item $file.FullName
}

আমি প্রথমটি ব্যবহার করেছি (এটি বোঝা সহজ), আমি দ্বিতীয়টি কাজ করতে পারি না (আমি সম্ভবত কিছু ভুল করছিলাম)।
স্টিবি

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

2

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

$backups | ForEach{ Remove-Item $_ }

আপনি আসলে পাইপের মাধ্যমে দির কমান্ড নিজেই ফরোয়ার্ড করতে পারেন এবং এমনকি ভেরিয়েবলটি নির্ধারণ করা এড়াতে পারেন:

Get-ChildItem -Path $Backuppath | 
Where-Object {
             ($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and `
             (-not $_.PSIsContainer) -and ($_.Name -like "backup*")
             } |
ForEach{ Remove-Item $_ }

আমি পঠনযোগ্যতার জন্য লাইন ব্রেকগুলি যুক্ত করেছি।

আমি পঠনযোগ্যতার জন্য কিছু লোককে ফরইচ / ইন-এর মতো বুঝতে পারি। কখনও কখনও ForEach- অবজেক্টটি কিছুটা লোমশ পেতে পারে, বিশেষত যদি আপনি reference _ রেফারেন্সটি অনুসরণ করা কঠিন হয়ে পড়ে বাসা বাঁধেন। যে কোনও হারে, এর মতো ছোট অপারেশনের জন্য এটি সঠিক। অনেক লোক এটির দ্রুত দাবি করে তবে আমি দেখতে পেয়েছি যে এটি কেবল সামান্যই।


+1 তবে পাওয়ারশেল 3 (সার্কো জুন 2012) দিয়ে foreachবিবৃতিটি আর পদক্ষেপে আসে না $null, সুতরাং ওপি দ্বারা বর্ণিত ত্রুটি আর ঘটে না। পাওয়ারশেল ব্লগ পোস্টের নতুন ভি 3 ভাষার বৈশিষ্ট্যগুলিতে "ফরইচ স্টেটমেন্টটি" নালার উপরে পুনরাবৃত্তি করে না " বিভাগটি দেখুন ।
jscott

1

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

$count = @(Get-ChildItem -Path $zipFilepath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")}).count;

if ($count -gt 0)
{
    $backups = Get-ChildItem -Path $zipFilepath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")};

    foreach ($file in $backups)
    {
        Remove-Item $file.FullName;
    }
}

1
মন্তব্যগুলিতে ব্যাখ্যা করার চেয়ে পোস্টটি দক্ষতার জন্য সম্পাদনা করেছি। আপনি যদি এটি পছন্দ না করেন তবে তা ফিরিয়ে দিন।
ড্যান

@ ড্যান - দোহ, বিশ্বাস করতে পারছি না যে আমি এটি চিহ্নিত করিনি, ধন্যবাদ।
স্টিবি

0

অ্যারেতে কোনও বিষয়বস্তু থাকলে মূল্যায়ন করতে নিম্নলিখিতটি ব্যবহার করুন:

if($backups.count -gt 0) { echo "Array has contents" } else { echo "Array is empty" }

যদি ভেরিয়েবলটি বিদ্যমান না থাকে তবে পাওয়ারশেল কেবল এটিকে মিথ্যা হিসাবে মূল্যায়ন করবে, সুতরাং এটি বিদ্যমান কিনা তা খতিয়ে দেখার দরকার নেই।


($ ব্যাকআপস.কাউন্ট-জিটি 0) যোগ করা $ ব্যাকআপগুলিতে 1 আইটেম থাকা সত্ত্বেও লুপটি কার্যকর করা বন্ধ করে দেয়। $ ব্যাকআপস কোড এমনকি এটির নিজস্ব কিছু আউটপুট দেয় না।
স্টিবি

@ স্টেবি আহ, আমার ধারণা, যে কোনও বস্তুর ধরণের ডেটা রয়েছে তার জন্য গণনা কার্যকর হয়নি। আমি পড়ার স্ক্যান করেছি এবং অনুমান করেছি যে এটি একটি অ্যারে ছিল।
ড্যান

$ গণনা = @ ($ ব্যাকআপ) c গণনা; প্রায় কাজ করে, কিন্তু যখন কোনও ফাইল থাকে না তবে f ($ count -gt 0) সত্য হয়!
স্টিবি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.