0

I am doing a PowerShell script, I want to show at the terminal a list of the files like I do in bash: ls | grep "foo.sh"

I tried to make:

dir | select-string -pattern "foo.sh"

but that looks inside the files, I want to filter by the name. I also tried

get-childItem | select-string -pattern "foo.sh"

but I have the same problem. Text-Path isn't working because I need a list of the files.

phuclv
  • 37,963
  • 15
  • 156
  • 475
E.rick
  • 103
  • 4
  • 2
    [never use `ls | grep`](https://unix.stackexchange.com/q/128985/44425) – phuclv Jan 11 '23 at 14:35
  • 3
    powershell is an object oriented language, everything literally is an object, if you want to filter objects use `Where-Object` and leave `Select-String` for matching strings. – Santiago Squarzon Jan 11 '23 at 14:39
  • 1
    Two asides: `dir` is simply an _alias_ of `Get-ChildItem`, so your two commands are equivalent. Both `grep` and `Select-String` interpret their patterns as _regexes_ by default, so to match a _literal_ `.` you'd have to either use `'foo\.sh'` or use `grep -F 'foo.sh'` / `Select-String -SimpleMatch -Pattern 'foo.sh'` – mklement0 Jan 11 '23 at 15:04
  • 1
    Does `Get-ChildItem -Filter '*foo.sh*'` produce what you want? – lit Jan 11 '23 at 16:08

2 Answers2

2

In bash you should never pipe ls output to other commands, and the same applies to PowerShell in this case1. Even worse, since PowerShell cmdlets return objects, not strings, piping Get-ChildItem output to Select-String makes absolutely zero sense because the object needs to be converted to string somehow, which may not return a useful string to match

The -Path parameter in Get-ChildItem already receives a pattern, just use it. That means to get the list of files whose names contain foo.sh just run

Get-ChildItem -Path *foo.sh*

or

ls *foo.sh*

In bash you do the same, and ls *foo.sh* returns more correct results than ls | grep foo.sh, and also faster. For listing foo.sh only obviously you just do ls foo.sh in both bash and PowerShell

For better performance in PowerShell you can also use

Get-ChildItem -Filter *foo.sh*

which filters out names right from the Provider level, which calls the Win32 API directly with the pattern


1Unlike bash, in PowerShell due to the object-oriented nature, sometimes you do pipe ls outputs to other commands for further processing, because you can operate on the original objects instead of strings so it'll still work for any files with special names or properties. For example

Get-ChildItem | Where-Object { $_.Parent -eq "abc" -and $_.LastWriteTime -lt (Get-Date) }
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • 2
    Good information in general, but note that piping Get-ChildItem output to Select-String _does_ make sense, because it is _special-cased_: it causes Select-String to search the input files' _contents_ - which is indeed what the OP accidentally ran into. – mklement0 Jan 11 '23 at 14:55
2

You are missing the -Name flag:

Get-ChildItem -Name | Select-String -Pattern "foo.sh"
akathimi
  • 1,393
  • 11
  • 3
    That avoids the original problem, but it seems like overkill in this case, given that `Get-ChildItem *foo.sh*` or `Get-ChildItem -Filter *foo.sh*` would do. That said, if you need sophisticated, regex-based name matching, this approach may be called for. – mklement0 Jan 11 '23 at 15:07
  • and it'll return files like foolsh, foodsh which may not be expected – phuclv Jan 12 '23 at 00:57