Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"get-childitem * -recurse" drops first-level directories

Tags:

powershell

Suppose we have the following directory structure:

~dir00
   |-> dir10
   |     |-> dir20
   |           |-> file1.txt
   |-> dir11
         |-> file2.txt

Now, suppose ~dir00 is the current directory. I would have expected the two commands
get-childitem * -recurse
and
get-childitem -recurse
to produce the same results. However, they do not. The behaviour of the second is what I would expect.

I am trying to write a small library of tools for use with our scripted processes. One tool I need to write is a tool to copy and backup sets of files. I get, as inputs, something that tells me what files/directories/etc. to copy. I have no way of knowing what the user may provide. They may provide a wild-card such as "*", they may provide a file name, they may provide the -recurse parameter, etc. etc. The inputs are fed to get-childitem. The inconsistency of the behaviour of get-childitem when the "path" is just "*" is a big problem. Why does get-childitem suddenly drop the first-level directories when fed a -path of "*" and the -recurse option? (Note that it only drops the first-level directories.) Is there any way I can prevent this odd behaviour?

Now, it gets more bizzare. If we put a file in the root directory, so the file structure becomes

~dir00
   |-> dir10
   |     |-> dir20
   |           |-> file1.txt
   |-> dir11
   |     |-> file2.txt
   |-> file3.txt

then the directories are suddenly NOT dropped. To reproduce this, just execute the following script:

cd $Env:temp
mkdir dir00\dir10\dir20 | out-null
cd dir00
mkdir dir11 | out-null
echo 'hello world 1'>dir10\dir20\file1.txt
echo 'hello world 2'>dir11\file2.txt
$list1 = get-childitem -recurse
echo 'Results of get-childitem -recurse: '
$list1
echo ''
echo 'Number of items:'
$list1.length
echo ''
$list2 = get-childitem * -recurse
echo 'Results of get-childitem * -recurse: '
$list2
echo ''
echo 'Number of items:'
$list2.length
echo ''
echo "hello world 3">file3.txt
$list3 = get-childitem * -recurse
echo 'Results of get-childitem * -recurse: '
$list3
echo ''
echo 'Number of items:'
$list3.length
echo ''
like image 671
David I. McIntosh Avatar asked Dec 19 '13 18:12

David I. McIntosh


1 Answers

This is because the path that you are feeding into Get-ChildItem is different.

When you execute:

Get-ChildItem -Recurse

You are saying the same as:

Get-ChildItem -Path . -Recurse

Or interpreted as: Get Child Item -Path starts at the current directory (dir00)

When you execute:

Get-ChildItem * -Recurse

You are saying, with the *, iterate through all items in the directory, feed those paths to Get-ChildItme, and then Recurse through those items. So the equivalent command that is executed is this:

$items = Get-ChildItem *
Get-ChildItem $items -Recurse

Which works out to:

Get-ChildItem -Path ./dir10 -Recurse
Get-ChildItem -Path ./dir11 -Recurse

Now, what you are seeing is an odd exception (or could be seen as a bug) to this behaviour, and it only happens in this case when you have a root directory that only contains folders and no files. If you create one file in the dir00:

echo 'hello world 1'>test1.txt

And then we execute

Get-ChildItem * -Recurse

It lists exactly the same as Get-ChildItem -Recurse. So you will only get different results only when you have root directories with no files, only folders.

like image 53
HAL9256 Avatar answered Nov 15 '22 03:11

HAL9256