7

I have a file that contains the some python code. There is a line that contains the following(including the quotes)

'hello "value"'

I want to search 'hello "value" in the file. Notice the unclosed quote. I'm using ripgrep with the folowing command:

rg -F 'hello "value"

The above command is not working for the input 'hello "value" in bash/ zsh. All i want is the literal match. I have used the flag F but because of unclosed quotes in the input string it is not working at all. I also tried enclosing the input inside single/ double quotes as so:

rg -F "'hello "value"" or rg -F ''hello "value"'

The above is not working as well.

I thought the F flag would tell ripgrep to consider the input literally as it is? How do I fix this?

ilkkachu
  • 138,973
  • One brute-force way is to backslash the shell metacharacters on the command line,as in: \'hello\ \"value\" Admittedly, this isn't the best of ways, but gets the job done. – guest_7 May 20 '21 at 19:16

3 Answers3

13

The text 'hello "value" as seen by the shell starts with a single quote and never ends it. You'll get a continuation prompt ($PS2, often >) asking for the rest of the string.

To search for something like this you would need to escape the quotes (both sorts) from the shell, which you can do like this

"'hello \"value\""

Or if you don't want to escape all the literal double quotes, quote the initial single quote and leave the rest of the string single-quoted

"'"'hello "value"'
^1 ^3            ^4      
  ^2
  • 1-2 double-quoted string containing the initial leading single-quote mark
  • 3-4 single-quoted string containing literal double-quote marks

If you have particularly complicated strings there would be nothing wrong with you reading the string from the script, where the shell can be instructed not to try to parse it, rather than on the command line, where it will attempt to parse it

#!/bin/bash
[[ $# -eq 0 ]] && IFS= read -rp "Enter search string: " item
rg -F "${1:-$item}"

Make the script executable and put it somewhere in your $PATH. If you provide something on the command line it will use it. If you don't, it will prompt for the string and you can enter one with as much complexity as you like.


As a footnote, possibly part of the confusion is the expectation from the Windows/DOS world that the program itself parses the command line. This is not the case in the UNIX/Linux world, where the shell parses the command line and passes the resulting arguments to the command. There is no way to tell to the shell not to parse the command line - that's what it does - so you need to work with that or else bypass the shell. Related reading is How to escape quotes in shell? and What is the difference between the “…”, '…', $'…', and $“…” quotes in the shell? , which explain in much more detail about quoting quotes, etc.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • I understood your point and it is working perfectly. What if it is a complex string, there is no simple way to tell ripgrep, hey i want to search "[]'some'string'90'';"$%6^~', please search it as it is. – Haris Muzaffar May 20 '21 at 16:06
  • 3
    Relating https://unix.stackexchange.com/questions/30903/how-to-escape-quotes-in-shell and https://unix.stackexchange.com/questions/503013/what-is-the-difference-between-the-and-quotes-in-th – Jeff Schaller May 20 '21 at 16:09
  • 3
    @HarisMuzaffar answer updated to offer an alternative to command-line processing – Chris Davies May 20 '21 at 17:27
5

If the string requires quoting from hell, you could take the help of heredoc to throw you a lifeline:

rg -Ff - <<\! your_file_python
'hello "value"
!

Alternatively, you can throw all these nasty regexes inside a file, away from the prying eyes of the shell, and have them used by ripgrep via the -f file option.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
guest_7
  • 5,728
  • 1
  • 7
  • 13
  • 2
    This useless-use-of-cat seems even more useless than most: you already explicitly mention - in the rg command line, and using cat just makes you mention it again. <<! can appear anywhere within the rg command, for example rg -Ff - <<! your_file_python – Peter Cordes May 21 '21 at 08:39
  • Fixed now. Thanks for the improvement. – guest_7 May 21 '21 at 19:26
3

To expand a bit on roaima's answer - if you use Bash you could use printf's %q modifier which causes printf to output the corresponding argument in a format that can be reused as shell input. A useful one-liner would be:

read -r &&  printf "%q\n" "$REPLY"

Type a string literally, press Return, and printf will display a correctly quoted string you can pass to shell commands.

Example:

$ read -r &&  printf "%q\n" "$REPLY"
'hello "value"'
\'hello\ \"value\"\'
$ echo \'hello\ \"value\"\'
'hello "value"'
terdon
  • 242,166