2011-02-14 12 views
5

मैं एक रिकर्सिव फ़ंक्शन लिखने की कोशिश कर रहा हूं जो एक सरणी में जानकारी वापस कर देगा, हालांकि जब मैं फ़ंक्शन में रिटर्न स्टेटमेंट डालता हूं तो यह कुछ प्रविष्टियों को याद करता है।रिटर्न के साथ पावरहेल रिकर्सन

मैं फ़ोल्डर के साथ एसीएल को प्राप्त करने वाले फ़ोल्डरों की एक निर्दिष्ट गहराई को फिर से देखने की कोशिश कर रहा हूं। मुझे पता है कि GetChildItem में एक रिकर्स विकल्प है, लेकिन मैं केवल फ़ोल्डरों के 3 स्तरों के माध्यम से कदम उठाना चाहता हूं।

नीचे दिए गए कोड का अंश मैं परीक्षण के लिए उपयोग कर रहा हूं। getACLS एक वापसी कथन (नीचे टिप्पणी की) के बिना कहा जाता है जब परिणाम हैं:

फ़ोल्डर 1

फ़ोल्डर 12

फ़ोल्डर 13

फ़ोल्डर 2

जब वापसी कथन है प्रयुक्त मुझे निम्न आउटपुट मिलता है:

फ़ोल्डर 1

फ़ोल्डर 12

तो ऐसा लगता है कि रिटर्न स्टेटमेंट रिकर्सिव लूप से बाहर निकल रहा है?

विचार यह है कि मैं की तरह एक बहुआयामी सरणी वापस करना चाहते [फ़ोल्डर का नाम, [acls], [[सबफ़ोल्डर, [अनुमतियाँ], [[...]]]]] आदि

cls 

function getACLS ([string]$path, [int]$max, [int]$current) { 

    $dirs = Get-ChildItem -Path $path | Where { $_.psIsContainer } 
    $acls = Get-Acl -Path $path 
    $security = @() 

    foreach ($acl in $acls.Access) { 
     $security += ($acl.IdentityReference, $acl.FileSystemRights) 
    } 

    if ($current -le $max) { 
     if ($dirs) { 
      foreach ($dir in $dirs) { 
       $newPath = $path + '\' + $dir.Name 
       Write-Host $dir.Name 
    #   return ($newPath, $security, getACLS $newPath $max ($current+1)) 
    #   getACLS $newPath $max ($current+1) 
       return getACLS $newPath $max ($current+1) 
      } 
     } 
    } elseif ($current -eq $max) { 
     Write-Host max 
     return ($path, $security) 
    } 
} 

$results = getACLS "PATH\Testing" 2 0 

उत्तर

7

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

function getACLS ([string]$path, [int]$max, [int]$current) { 

$dirs = Get-ChildItem -Path $path | Where { $_.psIsContainer } 
$acls = Get-Acl -Path $path 
$security = @() 
$results = @() 

foreach ($acl in $acls.Access) { 
    $security += ($acl.IdentityReference, $acl.FileSystemRights) 
} 

if ($current -lt $max) { 
    if ($dirs) { 
     foreach ($dir in $dirs) { 
      $newPath = $path + '\' + $dir.Name 
      $next = $current + 1 
      $results += (getACLS $newPath $max $next) 
     } 
    } else { 
     $results = ($path, $security) 
    } 
    return ($path, $security, $results) 
} elseif ($current -eq $max) { 
    return ($path, $security) 
} 
} 
2

अपडेट: मैं पहले जवाब को छोड़ रहा हूं और यहां नया कोड जोड़ रहा हूं। मैं देखता हूं कि आपके कोड के साथ कई समस्याएं हैं। यहां अपडेट किया गया है।

cls 

function getACLS ([string]$path, [int]$max, [int]$current) { 

    $dirs = Get-ChildItem -Path $path | Where { $_.psIsContainer } 
    $acls = Get-Acl -Path $path 
    $security = @() 

    foreach ($acl in $acls.Access) { 
     $security += ($acl.IdentityReference, $acl.FileSystemRights) 
    } 

    if ($current -lt $max) { 
     if ($dirs) { 
      foreach ($dir in $dirs) { 
       $newPath = $dir.FullName 
       $security 
       getACLS $newPath $max ($current+1) 
      } 
     } 
    } elseif ($current -eq $max) { 
     Write-Host max 
     return $security 
    } 
} 

$results = getACLS "C:\Scripts" 2 0 

यदि आप ऊपर देखते हैं, तो मैं वापसी का उपयोग नहीं कर रहा हूं। मैं ऑब्जेक्ट को GetACLs फ़ंक्शन से फेंक देता हूं। इसके अलावा, मैंने परीक्षण उद्देश्यों के लिए $ सुरक्षा पर वापस आने के लिए इसे संशोधित किया। मैं $ एसीएल में सभी एसीएल देख सकता हूं। यदि पहली स्थिति है ($ current -lt $ अधिकतम) तो मैंने पहली बार बदल दिया। यह नहीं होना चाहिए ($ वर्तमान-$ अधिकतम)।

मुझे यह बताएं कि आप क्या देख रहे हैं। मैं इसे अनुकूलित करना जारी रख सकता हूं।

========================================== पुराने === ========================================== रिटर्न फ़ंक्शन से बाहर निकल जाएगा।

मैं यहां पूरा समाधान नहीं दे रहा हूं लेकिन यह आपको एक विचार देना चाहता हूं कि इसे कैसे बदला जा सकता है।

आप अपनी आवश्यक जानकारी को कैप्चर करने के लिए पीएस कस्टम ऑब्जेक्ट का उपयोग कर सकते हैं। उदाहरण के लिए,

function GetItem { 
$itemsArray = @() 
Get-ChildItem C:\Scripts | ForEach-Object { 
    $itemsObject = New-Object PSObject 
    Add-Member -InputObject $itemsObject -MemberType NoteProperty -Name "FullName" -Value $_.FullName 
    Add-Member -InputObject $itemsObject -MemberType NoteProperty -Name "Name" -Value $_.Name 
    $itemsArray += $itemsObject 
} 
return $itemsArray 
} 

इस तरह आप ऑब्जेक्ट को वापस लौटने के बाद पूरी तरह से निर्मित जानकारी के साथ ऑब्जेक्ट वापस कर सकते हैं।

+0

सुनिश्चित नहीं है कि यह काम करेगा क्योंकि मुझे वस्तुओं को घोंसला करने की आवश्यकता होगी। – Rumpleteaser

+0

एक रिकर्सिव फ़ंक्शन को अलग-अलग विकल्पों को वापस करने में सक्षम होना चाहिए, भले ही यह रिकर्सिव केस का आधार मामला हो। तो यदि रिटर्न स्टेटमेंट पावरहेल में रिकर्सन तोड़ता है, तो रिकर्सन संभव नहीं है? या क्या उत्पादन का एक अलग प्रकार है? – Rumpleteaser

+0

मैंने आपकी आवश्यकताओं को गलत समझा होगा। मुझे स्क्रिप्ट पर वापस जाने दो और फिर इसे फिर से देखें। मुझे रिकर्सन भाग याद आया और आपको एक सामान्य टिप दी। PowerShell में रिकर्सन किया जा सकता है। – ravikanth

3

रिकर्सन में, मैं केवल return कथन का उपयोग करता हूं जहां मुझे रिकर्सन समाप्त करने की आवश्यकता होती है - केवल स्पष्टता के लिए। मैंने PowerShell में रिकर्सन का एक अच्छा सा किया है और यह अच्छी तरह से काम करता है। हालांकि आपको याद रखना होगा कि पावरशेल फ़ंक्शन अलग-अलग व्यवहार करते हैं।निम्नलिखित:

return 1,2 

के बराबर है:

1,2 
return 

दूसरे शब्दों में, कुछ भी आप एक चर में कब्जा या एक फ़ाइल को अनुप्रेषित (या $ नल) स्वचालित रूप से के उत्पादन में माना जाता है नहीं है समारोह। यहां एक काम करने वाला, रिकर्सिव फ़ंक्शन का एक साधारण उदाहरण दिया गया है:

function recursive($path, $max, $level = 1) 
{ 
    $path = (Resolve-Path $path).ProviderPath 
    Write-Host "$path - $max - $level" 
    foreach ($item in @(Get-ChildItem $path)) 
    { 
     if ($level -eq $max) { return } 

     recursive $item.PSPath $max ($level + 1) 
    } 
} 

recursive ~ 3 
संबंधित मुद्दे