Search code examples
powershellpowershell-5.0

Recursive Looping of Text Files to find lowest level


I have some text files, basically called jobs, where a job can contain another job or series of jobs, which can contain another job or series of jobs, etc... Essentially calling the job it contains.

The idea is to iterate through the top most file, step into the next lower file and so on until we reach the "lowest level".

The script I currently use is a loop, within a loop, within a loop. If I need to reach further down, I need to add another loop. In this example, we ignore the contents of the file having "JOB" in it.

Is there a better way to loop or iterate through all this without just adding more ForEach-Objects within ForEach-Objects?

cd C:\Files
$files = Get-ChildItem -Name

$files | ForEach-Object {

   $filename1 = $_
   write-host "$filename1"

   $step1 = Get-Content $filename1
   $step1 | ForEach-Object {

       $filename2 = $_
       write-host "`t$filename2" #We tab to show 2nd level job is inside 1st level job
       
       $step2 = Get-Content $filename2
       $step2 | ForEach-Object {

           $filename3 = $_
           $write-host "`t`t$filename3"

           $step3 = Get-Content $filename3
           $step3 | ForeEach-Object {#keep adding loops}
      }
   }
}

The jobs/files are contained all in a single directory as:

FILE1A
FILE1B
FILE1C
FILE2
FILE3
FILE4

etc..

Content of each file may look like:

JOB FILE1B

No limit to how many "JOB ???" may be contained inside the file.

There really is no convention to the naming of these files/jobs. When running the script, the result should look like this:

FILE1A
   FILE1B
FILE1C
   FILE2
   FILE3
   FILEXYZ
      FILEZYX
         FILE123
   FILEABC

Solution

  • As the others in comments have mentioned, one might use recursion to accomplish this.

    I hope I understood the question in my mock up.

    I have some files that look like this below, some containing lines with paths to other files and some not (0 length empty files)

        Directory: C:\temp\powershell\recursive_tests
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a---          18.08.2021    19:31            133 A1.txt
    -a---          18.08.2021    19:14              0 A1a.txt
    -a---          18.08.2021    19:31            133 A1b.txt
    -a---          18.08.2021    19:18              0 A1b1.txt
    -a---          18.08.2021    19:18              0 A1b2.txt
    -a---          18.08.2021    19:18              0 A1b3.txt
    -a---          18.08.2021    19:14              0 A1c.txt
    -a---          18.08.2021    19:31            133 B1.txt
    -a---          18.08.2021    19:31            133 B1a.txt
    -a---          18.08.2021    19:18              0 B1a1.txt
    -a---          18.08.2021    19:18              0 B1a2.txt
    -a---          18.08.2021    19:18              0 B1a3.txt
    -a---          18.08.2021    19:14              0 B1b.txt
    -a---          18.08.2021    19:31            133 B1c.txt
    -a---          18.08.2021    19:18              0 B1c1.txt
    -a---          18.08.2021    19:18              0 B1c2.txt
    -a---          18.08.2021    19:18              0 B1c3.txt
    

    As an example A1.txt looks like this

    C:\temp\powershell\recursive_tests\A1a.txt
    C:\temp\powershell\recursive_tests\A1b.txt
    C:\temp\powershell\recursive_tests\A1c.txt
    

    I imagine the code to process through them could look something like this

    function Get-FileInFile {
        param(
            [string[]]$Paths,
            $Level = 0
        )
        foreach ($path in $Paths) {
            Write-Host "$("`t" * $Level)$Path"
            $lines = Get-Content -Path $Path
            $newLevel = $Level + 1
            $lines | ForEach-Object {
                get-fileinfile -Path $_ -Level $newLevel
            }
        }
    }
    

    Output

    PS C:\temp\powershell\recursive_tests> get-fileinfile 'C:\temp\powershell\recursive_tests\A1.txt', 'C:\temp\powershell\recursive_tests\B1.txt'
    
    C:\temp\powershell\recursive_tests\A1.txt
            C:\temp\powershell\recursive_tests\A1a.txt
            C:\temp\powershell\recursive_tests\A1b.txt
                    C:\temp\powershell\recursive_tests\A1b1.txt
                    C:\temp\powershell\recursive_tests\A1b2.txt
                    C:\temp\powershell\recursive_tests\A1b3.txt
            C:\temp\powershell\recursive_tests\A1c.txt
    C:\temp\powershell\recursive_tests\B1.txt
            C:\temp\powershell\recursive_tests\B1a.txt
                    C:\temp\powershell\recursive_tests\B1a1.txt
                    C:\temp\powershell\recursive_tests\B1a2.txt
                    C:\temp\powershell\recursive_tests\B1a3.txt
            C:\temp\powershell\recursive_tests\B1b.txt
            C:\temp\powershell\recursive_tests\B1c.txt
                    C:\temp\powershell\recursive_tests\B1c1.txt
                    C:\temp\powershell\recursive_tests\B1c2.txt
                    C:\temp\powershell\recursive_tests\B1c3.txt
    

    Here I pass in only the 2 top level files A1.txt and B1.txt. Since all the files exist in the same folder I cannot use Get-ChildItem and just foreach through every file or files will be processed more than once, first being called initially by me and then again when their path is encountered in the sublevel files, so instead I just pass in the 2 that I know are the roots.