Reputation: 7102
I am looking for a search string inside a json file:
> type .\input.json
[
{"name": "moish"},
{"name": "oren"}
]
> type .\input.json | findstr /n /l "\`"name\`": \`"or"
2: {"name": "moish"},
3: {"name": "oren"}
How come moish
entry is found? what am I missing?
Upvotes: 1
Views: 221
Reputation: 174435
Note: The quoted lines below, originally a direct part of the answer, turned out not to apply to the problem at hand, because the escaping in the question is correct (the only thing missing was placing /c:
directly before the string to make findstr.exe
search for it as a whole).
See this answer for a more comprehensive analysis of the problem.
Escape the literal quotation marks by doubling them:
type input.json |findstr /n /l """name"": ""or"
... or use single-quotes to qualify the search term:
type input.json |findstr /n /l '"name": "or'
.... or perhaps use the native PowerShell cmdlet Select-String
instead of findstr
:
Select-String -LiteralPath input.json -Pattern '"name": "or'
Upvotes: 1
Reputation: 437062
Prepend /c:
to your search string in order to make findstr
treat it as a single string to search for:
Get-Content .\input.json | findstr /n /l /c:"\`"name\`": \`"or" # Note the /c:
Note the use of the Get-Content
cmdlet for reading a file line by line, which type
is a built-in alias for in PowerShell.
Note:
By default, if a search string contains spaces, findstr
searches for the occurrence of any of the space-separated words, i.e., "name"
or "or
, causing both lines to match. /c:
signals that the string as a whole string should be searched for (either as a regular expression, by default, or as a literal string, with /l
)
Except for the missing /c:
, your search string was correct, but you could have simplified by using a verbatim (single-quoted) string ('...'
):
... | findstr /n /l /c:'\"name\": \"or'
\
-escaping of the embedded "
chars. is a requirement either way, up to at least PowerShell 7.2.x, even though it shouldn't be necessary.
PSNativeCommandArgumentPassing
enabled and the $PSNativeCommandArgumentPassing
preference variable set to either 'Standard'
or 'Windows'
, the \
-escaping is no longer needed, because PowerShell then (finally) does it for you; that is, findstr /n /l /c:'"name": "or'
would suffice.PowerShell alternative: Select-String
:
As shown in Mathias R. Jessen's answer, you may alternatively use the Select-String
cmdlet, the more powerful PowerShell counterpart to findstr.exe
, not least to avoid quoting headaches (see above) and potential character-encoding issues.
Like findstr.exe
, Select-String
uses regular expressions by default; use -SimpleMatch
to opt for literal matching.
Unlike findstre.exe
, Select-String
is case-insensitive by default (as PowerShell generally is). Use -CaseSensitive
to make matching case-sensitive.
Select-String
wraps matching lines in objects that include metadata about each match; if you're interested in the line text only, use -Raw
in PowerShell (Core) 7+, or pipe to ForEach-Object Line
in Windows PowerShell.
While piping lines read from a file via Get-Content
works, it is much slower than the passing the file path as an argument directly to Select-String
, via its -LiteralPath
parameter (you may also pipe file-info objects obtained with Get-ChildItem
to it).
Thus, the equivalent of your (corrected) findstr.exe
call is:
Select-String -LiteralPath .\input.json -CaseSensitive -SimpleMatch -Pattern '"name": "or'
# Alternative:
Get-ChildItem .\input.json |
Select-String -CaseSensitive -SimpleMatch -Pattern '"name": "or'
You'll get the following output in the console (note the output-line prefix consisting of the file name and the line number):
input.json:3: {"name": "oren"}
Note that this is the for-display representation of the object of type [Microsoft.PowerShell.Commands.MatchInfo]
that Select-String
emitted for the matching line.
Upvotes: 1