खाली सूची होने पर फॉरच लूप को सुरक्षित रखें


10

Powershell v2.0 का उपयोग करके मैं X दिनों से अधिक पुरानी किसी भी फ़ाइल को हटाना चाहता हूं:

$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)

इनमें से कोई भी काम नहीं करता है, अगर सूची खाली है तो फ़ॉरच लूप को दर्ज करने से रोकने का अनुशंसित तरीका क्या होगा?


@Dan - दोनों ($ बैकअप> 0) और (@ ($ बैकअप) .count -gt 0) दोनों की कोशिश की है, लेकिन जब कोई फ़ाइल नहीं है, तो अपेक्षित रूप से काम न करें।
SteB

जवाबों:


19

पॉवर्सशेल 3 के साथ foreachबयान पर कोई प्रभाव नहीं पड़ता है $nullऔर ओपी द्वारा वर्णित समस्या नहीं होती है।

से विंडोज PowerShell ब्लॉग पोस्ट नई वी 3 भाषा विशेषताएं :

फॉरएच स्टेटमेंट $ null से अधिक नहीं है

PowerShell V2.0 में, अक्सर लोग आश्चर्यचकित थे:

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

got here

यह स्थिति अक्सर तब आती है जब कोई cmdlet किसी ऑब्जेक्ट को वापस नहीं करता है। PowerShell V3.0 में, आपको $ null से अधिक चलने से बचने के लिए कोई कथन जोड़ने की आवश्यकता नहीं है। हम आपके लिए इसका ध्यान रखते हैं।

PowerShell के $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सरणी में लिपटे cmdlet पर ध्यान दें । यह उन कार्यों के साथ भी काम करेगा जो वापस आ सकते हैं $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
}

मैंने पहले एक का उपयोग किया है (यह समझना आसान है), मुझे काम करने के लिए दूसरा नहीं मिला (मैं शायद कुछ गलत कर रहा था)।
SteB

@SteB आप सही हैं, मेरा उदाहरण खराब तरीके से समझाया गया था (यह अभी भी है), लेकिन मैंने आपके उदाहरण कोड सहित एक संपादन प्रदान किया है। व्यवहार की बेहतर व्याख्या के लिए, कीथ हिल के ब्लॉग पर कृपया इस पोस्ट को देखें , वह न केवल पॉवरशेल विशेषज्ञ हैं, बल्कि मुझसे भी बेहतर लेखक हैं। कीथ स्टैकऑवरफ्लो पर सक्रिय है , मैं आपको (या पीएस में रुचि रखने वाले किसी व्यक्ति) को उसके सामान की जांच करने के लिए प्रोत्साहित करूंगा।
14:13

2

मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन मैं यह बताना चाहूंगा कि ForEach-Object cmdlet को ForEach कुंजी शब्द का उपयोग करने में कोई समस्या नहीं है। तो आप डीआईआर को फॉरएच के परिणामों को पाइप कर सकते हैं और $ _ का उपयोग करके फ़ाइल को संदर्भित कर सकते हैं, जैसे:

$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 / In पठनीयता के लिए पसंद करते हैं। कभी-कभी ForEach-object को थोड़े से बाल मिल सकते हैं, खासकर यदि आप घोंसले के शिकार हैं क्योंकि $ _ संदर्भ का पालन करना कठिन हो जाता है। किसी भी दर पर, इस तरह के एक छोटे ऑपरेशन के लिए यह एकदम सही है। कई लोग यह भी कहते हैं कि यह तेज है लेकिन मैंने पाया है कि केवल थोड़ा ही होना चाहिए।


+1 लेकिन पॉवर्सशेल 3 के साथ (लगभग जून 2012) foreachबयान में अब कदम नहीं है $null, इसलिए ओपी द्वारा वर्णित त्रुटि अब नहीं होती है। Powershell Blog की पोस्ट नई V3 लैंग्वेज फीचर्स में "ForEach स्टेटमेंट $ null से अधिक पुनरावृति नहीं करता है" अनुभाग देखें ।
jscott

1

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

$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
मैंने पोस्ट को दक्षता के लिए संपादित किया है क्योंकि यह टिप्पणियों में व्याख्या करने की तुलना में आसान था। अगर आपको यह पसंद नहीं है तो बस इसे वापस कर दें।
दान

@Dan - दोह, विश्वास नहीं होता कि मैं स्पॉट नहीं किया, धन्यवाद।
SteB

0

मूल्यांकन के लिए निम्न का उपयोग करें यदि सरणी में कोई सामग्री है:

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

यदि चर मौजूद नहीं है, तो पॉवर्सशेल बस इसे असत्य के रूप में मूल्यांकन करेगा, इसलिए यदि यह मौजूद है तो जांच की कोई आवश्यकता नहीं है।


अगर ($ backups.count -gt 0) जोड़ रहा है, तब भी जब $ बैकअप में 1 आइटम हो, तो लूप निष्पादित करना बंद कर देता है। $ backups.count यहां तक ​​कि यह अपने आप में कुछ भी आउटपुट नहीं करता है।
SteB

@SteB आह, मुझे लगता है कि डेटा जो भी वस्तु प्रकार धारण कर रहा है उसके लिए गणना लागू नहीं है। मैंने रीड स्कैन किया और माना कि यह एक एरे था।
दान

$ गिनती = @ ($ बैकअप) .count; लगभग काम करता है, लेकिन जब कोई फ़ाइल नहीं होती है तो f ($ count -gt 0) सच है!
SteB
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.