How can I escape a single quote in ag (without using double quotes) - ag

How can I escape a single quote in ag when searching for an expression like this one?
ag ''react-redux''
I'm aware that "'react-redux'" is one solution in this scenario, but I'd like a solution that lets me use single quotes. That way I don't have to worry about the complex escape sequences required by $, %, etc. when using double quotes.

you can use \x27 to represent single quotes. (\x27 is just the ascii code for single quotes)
thus, you can use:
ag '\x27react-redux\x27'
ref: How to escape single quote in sed? --stackoverflow

While \x27 works, it's obscure. The standard approach is triple single quotes. So, if you want to escape single quotes around 'react-redux' you'd surround each single quote with a pair of single quotes: '''react-redux'''.
For example:
$ag '''DD-MON-YYYY''' users.sql
19: TO_CHAR(lock_date, 'DD-MON-YYYY') AS lock_date,
20: TO_CHAR(expiry_date, 'DD-MON-YYYY') AS expiry_date,
23: TO_CHAR(created, 'DD-MON-YYYY') AS created,
So, a trivial example to only match quoted items:
$touch test.txt
$echo value >> test.txt
$echo '''value''' >> test.txt
$echo value >> test.txt
$ < test.txt
value
'value'
value
$ ag '''value''' test.txt
2:'value'

Related

Add backslash before single and double quote

I am trying to add backslash before single and double quote. The problem that I have is that I want to exclude triple quote.
What I did is as for now:
for single quote:
sed -e s/\'/\\\\\'/g test.txt > test1.txt
for double quote:
sed -e s/\"/\\\\\"/g test.txt > test1.txt
I have text like:
1,"""Some text XM'SD12X""","""Some text XM'SD12X""","""Auto " Moto " Some text"Some text"""
What I want is:
120,"""Some text\'SD12X""","""Some text XM\'SD12X""","""Auto \" Moto \" Some text\"Some text"""
If perl is okay:
perl -pe 's/"{3}(*SKIP)(*F)|[\x27"]/\\$&/g'
"{3}(*SKIP)(*F) don't change triple double quotes
use (\x27{3}|"{3})(*SKIP)(*F) if you shouldn't change triple single/double quotes
|[\x27"] match single or double quotes
\\$& prefix \ to the matched portion
With sed, you can replace the triple quotes with newline character (since newline character cannot be present in pattern space for default line-by-line usage), then replace the single/double quote characters and then change newline characters back to triple quotes.
# assuming only triple double quotes are present
sed 's/"""/\n/g; s/[\x27"]/\\&/g; s/\n/"""/g'

How to use sed to add double quotes around every word, excluding colons and commas

I want to alter a string so that I have double quotes around every "word," excluding colons and commas ':,'.
For example, my input may look like:
[ANALYSIS:true, RESTRICTED:false, STRING_PARAMETER:World,
JOB_NAME:Hello_Jenkins]
but I want it to appear as
["ANALYSIS":"true", "RESTRICTED":"false", "STRING_PARAMETER":"World",
"JOB_NAME":"Hello_Jenkins"]
I've been using something like (using '_' as the delimiter)
'echo ${params} | sed -i "s_\'/\\([^:]*\\):/i\'_\'"$1" :\'_g" '
based off of what I've found online, yet it makes no changes to my string.
> sed -r 's/[^], :[]+/"&"/g' file
["ANALYSIS":"true", "RESTRICTED":"false", "STRING_PARAMETER":"World", "JOB_NAME":"Hello_Jenkins"]
In the above sed we exclude colons, commas, the brackets and the spaces, as your example says so. If your case is not fully represented by your example, you could modify the excluded characters, but the order of the brackets in the expression is important.
$ echo '[ANALYSIS:true, RESTRICTED:false, STRING_PARAMETER:World, JOB_NAME:Hello_Jenkins]' |
sed 's/[[:alnum:]_]\+/"&"/g'
["ANALYSIS":"true", "RESTRICTED":"false", "STRING_PARAMETER":"World", "JOB_NAME":"Hello_Jenkins"]
or if you have to exclude instead of include chars in the regexp:
$ echo '[ANALYSIS:true, RESTRICTED:false, STRING_PARAMETER:World, JOB_NAME:Hello_Jenkins]' |
sed 's/[^][,: ]\+/"&"/g'
["ANALYSIS":"true", "RESTRICTED":"false", "STRING_PARAMETER":"World", "JOB_NAME":"Hello_Jenkins"]

sed to edit a line on a file

I have a line value I need to update on a file,
export const ADDRESS_ORIGIN = 'chupa-cabra.muz.id';
Im tryging to update with:
sed -i '' 's/ADDRESS_ORIGIN ="[0-9.]*"/ADDRESS_ORIGIN ="'chapuza'"/' constants.js
But the value for
ADDRESS_ORIGIN
Is not updating, I think my REGEX is very wrong, how can I update the value?
Thanks!
There is no way "[0-9.]*" can match 'chupa-cabra.muz.id' but without knowing what the permitted values look like we can only speculate. Perhaps '[^']*' would do what you want, though you need to understand the mechanisms of shell quoting in order to correctly get it through to sed. In this particular case, the simplest by far is to use double quotes around the sed script instead of single:
sed -i '' "s/ADDRESS_ORIGIN = *'[^']*'/ADDRESS_ORIGIN = 'chapuza'/" constants.js
though if you know what you are doing, you could also do it with alternating single and double quotes:
sed -i '' 's/ADDRESS_ORIGIN = *'"'[^']*'"'/ADDRESS_ORIGIN = '"'chapuza'/" constants.js
The basic mechanism here is that adjacent strings will be glued together into one string by the shell. So "a"'b' is a a double-quoted a followed by a single-quoted b. After the shell is done parsing it, you get the string ab. Now for fun, imagine that a is a literal single quote, and b is a literal double quote.
... Or perhaps you only want to replace the first token before the dot? Then '[^.']*\. would match and you'd want to replace with 'chapuza. Or use a back reference '[^.']*\(['.]\) and replace with 'chapuza\1
In the general case, of course, double quotes have different semantics than single, so if your script uses characters which will be mangled by the shell when you switch quotes, you need to add a backslash before them, or switch to the "seesaw quoting" mechanism I described above. But in this particular case, your example script doesn't require any modifications to adapt to double quotes.
I assume you are on macOS because of the way you are using in-place editing; this should work:
sed -E -i '' "s#(ADDRESS_ORIGIN = )'.*'#\1'chapuza'#g"
Result:
export const ADDRESS_ORIGIN = 'chapuza';
Why should it?
You missed the space after the equal sign, and double quotes " will literally match double quotes not single quotes ', and [0-9.]* will match consecutive digits and dots.
An alternative to the bewildering quotes alternating would be use ASCII inside the regex:
sed 's/ADDRESS_ORIGIN *= *\x27[^\x27]*\x27/ADDRESS_ORIGIN = \x27chapuza\x27/'
or
sed 's/\(ADDRESS_ORIGIN\) *= *\x27[^\x27]*\x27/\1 = \x27chapuza\x27/'
Or better still, since there could be double quotes around the value, you can consider both situation by this:
sed -E 's/(ADDRESS_ORIGIN) *= *([\x27\x22])[^\039\034]*\2/\1 = \x27chapuza\x27/'
Where \x27 = \039 = ', \x22 = \034 = " in RegEX.
Like this:
$ echo export const ADDRESS_ORIGIN = \"chupa-cabra.muz.id\"\;|sed -E 's/(ADDRESS_ORIGIN) *= *([\x27\x22])[^\039\034]*\2/\1 = \x27chapuza\x27/'
export const ADDRESS_ORIGIN = 'chapuza';

String replace on a very large file

I have a giant text file that is JSON. You can see it here: http://api.mtgdb.info/cards/. I have saved this JSON to a file called cards.json.
In cards.json, I need to escape every single quote ' with a backslash \.
So I need to replace ' with \'.
Usually this is trivial in any editor, however the file is too large. How can I escape all single quotes in this string?
What I've tried:
I tried using sed. My command was sed s/\'/\\\'/ cards.json > cards_cleaned.json. However the cards_cleaned.json file did not have any escaped ', it was just an exact copy of cards.json. Sed works when i do sed s/\'/foobar/ cards.json > cards_cleaned.json, so I'm assuming something is wrong with my escaping backslashes.
I tried using vim. I opened cards.json in vim $ vi cards.json. Then I tried a global string replace using :%s/'/\'/g. This did not change anything in the file.
While #anubhava's or #gboffi's answers works, they produces and INVALID JSON.
JSON allows only few characters after the backslash:
\"
\\
\/
\b
\f
\n
\r
\t
\u four-hex-digits
e.g. the part of the following original (correct) JSON
[
{
"description" : "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller.",
"rarity" : "Rare",
"name" : "Ankh of Mishra"
}
]
you want to get
[
{
"description" : "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land\'s controller.",
"rarity" : "Rare",
"name" : "Ankh of Mishra"
}
]
#e.g. instead of the land's want land\'s
But this is an INVALID JSON.
So, if you (for some strange reason) want have the backslash, you need to use double \\, such:
[
{
"description" : "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land\\'s controller.",
"rarity" : "Rare",
"name" : "Ankh of Mishra"
}
]
Solution (for both)
with perl
perl -pE "s/'/\\\'/g" < mtg_cards.json > cards.malformed.json
#changes "land's" to wrong "land\'s"
and
perl -pE "s/'/\\\\'/g" < mtg_cards.json > card_with_double_BS.json
#changes "land's" to "land\\s"
Ps: Because your file is only one long (30MB) line, the vim has some problems. You can pretty print (fold and indent) the JSON, before editing. Many tools here, i'm using the json_xs command from the JSON_XS perl package. After "prettyfying" you can use the vim safely.
You need to use double quotes in the shell to avoid quoting the single quote character, but the you have to be careful because the shell, for a double quoted string, use the backslash as a quoting character
$ echo "eoieriou'iouou'oiuiouiuo"|sed "s/'/\\'/g"
eoieriou'iouou'oiuiouiuo
and the command that sed is trying to execute is s/'/\'/g but sed quoting character is the backslash, so that you substitute each single quote with a single quote...
We have to quote the backslash also when it arrives to sed, so let's try
$ echo "eoieriou'iouou'oiuiouiuo"|sed "s/'/\\\\'/g" # Four (4) backslashes in a row
eoieriou\'iouou\'oiuiouiuo
$
That's OK, isn't it? because sed is instructed to do s/'/\\'/g so that the quoted character, from the POV of sed, is the backslash itself...
Please note that the quotes, single or double, are not special characters from the POV of sed, they're special only in the context of the shell.
In Vi you will need to escape the \ character.
Try using
:%s/'/\\'/g
For me it worked.
Test.txt
\'\'\' \'\'\'
You need to double escape the backelas, so use:
sed -i.bak "s/'/\\\\'/g" cards.json
You can use like this, in vim.
:%s/'/\\\'/g
In sed,
sed "s/'/\\\'/g" filename
Here is an awk version:
cat file
hi'more data here'
awk '{gsub(g,"\\"g)}1' g="'" file
hi\'more data here\'
Or if you need double backslash:
awk '{gsub(g,"\\\\"g)}1' g="'" file
hi\\'more data here\\'
sed "s/'/\\\\&/g" cards.json > cards_cleaned.json
no need of your first escaped in search pattern \'
you should surround by double quote (single if single quote was not the char to change) and escape the escape due to double quote used at shell level in this case

sed: Replacing a double quote in a quoted field within a delmited record

Given an optionally quoted, pipe delimited file with the following records:
"foo"|"bar"|123|"9" Nails"|"2"
"blah"|"blah"|456|"Guns "N" Roses"|"7"
"brik"|"brak"|789|""BB" King"|"0"
"yin"|"yang"|789|"John "Cougar" Mellencamp"|"5"
I want to replace any double quotes not next to a delimiter.
I used the following and it almost works. With one exception.
sed "s/\([^|]\)\"\([^|]\)/\1'\2/g" a.txt
The output looks like this:
"foo"|"bar"|123|"9' Nails"|"2"
"blah"|"blah"|456|"Guns 'N" Roses"|"7"
"brik"|"brak"|789|"'BB' King"|"0"
"yin"|"yang"|789|"John 'Cougar' Mellencamp"|"5"
It doesn't catch the second set of quotes if they are separated by a single character as in Guns "N" Roses. Does anyone know why that is and how it can be fixed? In the mean time I'm just piping the output to a second regex to handle the special case. I'd prefer to do this in one pass since some of the files can be largish.
Thanks in advance.
You can use substitution twice in sed:
sed -r "s/([^|])\"([^|])/\1'\2/g; s/([^|])\"([^|])/\1'\2/g" file
"foo"|"bar"|123|"9' Nails"|"2"
"blah"|"blah"|456|"Guns 'N' Roses"|"7"
"brik"|"brak"|789|"'BB' King"|"0"
"yin"|"yang"|789|"John 'Cougar' Mellencamp"|"5"
sed kind of implements a "while" loop:
sed ':a; s/\([^|]\)"\([^|]\)/\1'\''\2/g; ta' file
The t command loops to the label a if the previous s/// command replaced something. So that will repeat the replacement until no other matches are found.
Also, perl handles your case without looping, thanks to zero-width look-ahead:
perl -pe 's/[^|]\K"(?!\||$)/'\''/g'
But it doesn't handle consecutive double quotes, so the loop:
perl -pe 's//'\''/g while /[^|]\K"(?!\||$)/' file
You may like to use \x27 instead of the awkward '\'' method to insert a single quote in a single quoted string. Works with perl and GNU sed.