Sed issue parenthesis escape - bash

I try to substitute a line in my .sql file with the sed command.
I encountered an issue when i try to "escape" the last parenthesis of the line.
I tried to escape it with a backlash , used simple and double quotes around it but the problem persist.
sed -i "s|\(select dbms_metadata.get_ddl('PACKAGE',\).*|\1"'${var}','PRC_BNE_JZ') from dual;"|" backup_script.sql
The actual result is the following error :
syntax error near unexpected token `)'
The expected result is to understand my error.

Untested since you didn't provide any sample input/output to test against but this might be what you're looking for:
sed -i 's/\(select dbms_metadata.get_ddl('\''PACKAGE'\'',\).*/\1'"${var}"','\''PRC_BNE_JZ'\'') from dual;/' backup_script.sql
Don't use | as a delimiter since it's an ERE metacharacter and so makes your code confusing to read at best and can cause problems if/when you decide to use EREs later (via the -E arg).
Do always use single quotes around scripts and strings unless you have a very specific reason why you must not do so and fully understand all the implications.

I do everything in single quotes, to prevent strange expansions. To have a single quote in the string, I use '\'' as in ' string '\'' rest of string '. To have a variable I use '"$var"' as in ' string '"$var"' rest of string to have it properly expanded and concatenated with the rest of the string.
The following works:
> var=var
> echo "select dbms_metadata.get_ddl('PACKAGE'," |
> sed 's|\(select dbms_metadata.get_ddl('\''PACKAGE'\'',\).*|\1'\'"${var}"\'','\''PRC_BNE_JZ'\'') from dual;|'
select dbms_metadata.get_ddl('PACKAGE','var','PRC_BNE_JZ') from dual;
But probably using " is probably easier in this case, as the string uses ' everywhere, as in:
sed "s|\(select dbms_metadata.get_ddl('PACKAGE',\).*|\1'${var}','PRC_BNE_JZ') from dual;|"
The error comes from the shell that can't parse the arguments. Ex. for the following:
> echo abc)
main.sh: line 2: syntax error near unexpected token `)'
main.sh: line 2: `echo abc)'
The following happens in your command:
sed -i " bla bla "'${var}','PRC_BNE_JZ') from dual;"|" backup_script.sql
^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^ - could be 4th argument
^ - unquoted `)` is parsed by bash, as in subshell `( ... )`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 2nd argument
^^ - 1st argument to sed command
^^^ - run sed command

Related

Bash multi-line command with input | output

My question is a simple one. I am looking to simply format my bash code into something a little more readable for other users .. While this works:
mysql --login-path=main-data -N -e "SELECT section_id FROM db.table WHERE contractor_id = '1'" | while read contractor_info_id; do
#......//
done
I don't understand why the backslash doesn't work with a input output statement separated by | .. IE
mysql --login-path=main-data -N -e "SELECT section_id\
FROM db.table\
WHERE contractor_id = '1'" | while read contractor_info_id; do
#......//
done
It generates a fatal error Syntax error: "done" unexpected
Why does multi-line formatting work on a single output command such as:
long_arg="my very long string\
which does not fit\
on the screen"
But not on an output | input command ?
The reason the escaped line ending does not work in your mysql use case is that mysql does not require an escaped line ending. The text between the two double quotes is treated as the string, and escaped characters are no interpreted. (eg: \t would not put in a tab). You can se this in action with these examples:
$ echo "Hello from line one
> and hello from line two"
Hello from line one
and hello from line two
$ echo Hello from line one \
> and also from line one
Hello from line one and also from line one
TL;DR: Within double-quotes, the slash and CR is treated as part of the string, not interpreted as an escape character.
Backslashes not needed inside quotes, and SQL isn't usually picky about extra whitespace anyway.
I don't have mysql installed here, but try this and let me know if it doesn't behave...
mysql --login-path=main-data -N -e "
SELECT section_id
FROM db.table
WHERE contractor_id = '1'
" | while read contractor_info_id
do echo $contractor_info_id
done
mysql "..." | while read contractor_info_id; do
#......//
done
Syntax error: "done" unexpected
This error is coming from bash, not from mysql, so we can rule out anything inside the double quotes. It doesn't matter what you're doing with backslashes there.
Do you actually have anything in place of #......//? You need at least one command inside the loop, otherwise you'll get this "done" unexpected error. Try :, a no-op command. That'll at least get rid of the syntax error.
mysql "..." | while read contractor_info_id; do
:
done
"SELECT section_id\
FROM db.table\
WHERE contractor_id = '1'"
The backslashes won't cause bash any heartburn but they do lead to invalid SQL. Once the shell deletes the backslashes and newlines you're left with:
"SELECT section_idFROM db.tableWHERE contractor_id = '1'"
To fix that you can either add spaces, or just leave out the backslashes. MySQL doesn't care if there are newlines, nor does bash, so you can stick with what you wrote originally.
"SELECT section_id
FROM db.table
WHERE contractor_id = '1'"
The reason for this happening to me was a unique issue I was having with my IDE .. It was inserting an actual character for a line break rather than just a physical line-break itself. The problem wasn't the syntax I was attempting, rather the inserted characters on save. Thanks to all who thoughtfully answered my question. My original un-escaped syntax was correct to begin with.

Replace Double quotes with space

this is perhaps one of the most discussed topics here. I tried almost all the commands and other tweaks found here, but something doesn't seems to be doing well.
i would want to replace all the double quotes in my file with whitespace/blank
I'm seeing the below error when i tried to execute this command.
sed "s/"/ \''/g' x_orbit.txt > new.tx
sed: -e expression #1, char 3: unterminated `s' command
You're close. Just use single quotes, so the shell doesn't try to expand the metacharacters in your sed command:
sed 's/"/ /g' x_orbit.txt > new.txt
You could try tr for example:
tr '"' ' ' < x_orbit.txt > new.txt
The script you provided:
sed "s/"/ \''/g' x_orbit.txt > new.tx
means:
sed # invoke sed to execute the following script:
" # enclose the script in double quotes rather than single so the shell can
# interpret it (e.g. to expand variables like $HOME) before sed gets to
# interpret the result of that expansion
s/ # replace what follows until the next /
" # exit the double quotes so the shell can now not only expand variables
# but can now do globbing and file name expansion on wildcards like foo*
/ # end the definition of the regexp you want to replace so it is null since
# after the shell expansion there was no text for sed to read between
# this / and the previous one (the 2 regexp delimiters)
\' # provide a blank then an escaped single quote for the shell to interpret for some reason
'/g' # enclose the /g in single quotes as all scripts should be quoted by default.
That is so far off the correct syntax it's kinda shocking which is why I dissected it above to try to help you understand what you wrote so you'll see why it doesn't work. Where did you get the idea to write it that way (or to put it another way - what did you think each character in that script meant? I'm asking as it indicates a fundamental misunderstanding of how quoting and escaping works in shell so it'd be good if we could help correct that misunderstanding rather than just correct that script.
When you use any script or string in shell, simply always enclose it in single quotes:
sed 'script' file
var='string'
unless you NEED to use double quotes to let a variable expand and then use double quotes unless you NEED to use no quotes to let globbing and file name expansion happen.
An awk version:
awk '{gsub(/"/," ")}1' file
gsub is used for the replace
1 is always true, so line is printed

BSD sed; error "unescaped newline inside substitute pattern" when run from script

I am attempting to use (BSD) sed to modify my /etc/gettytab. The goal is to modify this entry:
P|Pc|Pc console:\
:ht:np:sp#9600:
to this entry:
P|Pc|Pc console:\
:ht:np:sp#115200:\
:cl=\E[H\E[2J:
If I issue the command below (it's on two lines), it works perfectly.
# sed -in ' /P|Pc|Pc console/,/^#/ s/9600:/115200:\\\\
:cl=\E[H\E[2J:/' /etc/gettytab
However, if I use the exact same command (literally copy/paste it) in a script, I get an error message:
sed: 1: " /P|Pc|Pc console/,/^#/ ...": unescaped newline inside substitute pattern
Searching, I found this post: unescaped newline inside substitute pattern which talks about the trailing /, but I have that in my pattern.
If anyone can assist with what I am doing wrong, I would greatly appreciate it.
Within your script, you escape newlines with a \, and you escape the \ that you're embedding into your output so that it will be interpreted literally. If my math is right, that comes to THREE, not four backslashes.
$ cat i
P|Pc|Pc console:\
:ht:np:sp#9600:
$ cat i.sh
#!/bin/sh
# ┏━━━ escapes the next character,
# ┃┏━━ literal backslash for output,
# ┃┃┏━ escapes the newline.
sed -ne '/^P|/,/^#/ s/9600:/115200:\\\
:cl=\E[H\E[2J:/' -e p i
$ ./i.sh
P|Pc|Pc console:\
:ht:np:sp#115200:\
:cl=E[HE[2J:
$

Replace in a file with variable containing underscore

File Content(file.txt):
table=$table_name
data=$data_name
Shell Script:
name=kush_123
cat file.txt | grep 'table' | sed "s\table_name\$name\g"
Expected output:
table=$kush_123
This gives error
unterminated s command
if the name variable has _ in it.
If you really want to use a backslash as a delimiter, it needs to be escaped itself so that the double-quoted string preserves it before passing to sed:
sed "s\\table_name\\$name\\g"
Otherwise, sed receives the string stable_name$nameg as its script. (\t, \$, and \g expand to t, $, and g, respectively). In this case, the letter t (as it immediately follows the s) is used as the delimiter, and the error results because there aren't enough ts in the result to provide a complete command.
Of course, if you try this, sed should complain that a backslash cannot be used as the delimiter for the s command. Use a different character:
sed "s/table_name/$name/g"
In general, building such scripts dynamically is fragile, because it assumes you know the value of $name doesn't contain your chosen delimiter.
On more investigation i found out the variable name has trailing spaces as the variable value was passed from python code. I trimmed extra spaces and it worked. Thanks :)

Bash grep is not working with apostrophe

I've tried to run this code:
lsof | grep "/file/path/"
If the file has this sign:
`
I get an error:
syntax error near unexpected token '`'
I've tried to escape this sign with \, but I got the same error.
Operation System: CentOS 6
The ` character (often called a "backquote") is interpreted specially by the shell, even when surrounded by quotes.
Specifically, `cmd args` means "execute the command cmd args and replace the backquoted string with the output from that command." If it is surrounded by quotes -- "`cmd args`" -- the replaced string will not undergo word-splitting or pathname-expansion. (That's usually what you want, so quoted backquotes are common.)
That syntax has been deprecated for a long time, but it is still accepted. New code should use $(cmd args) instead. As above, you usually want to avoid word-splitting and pathname-expanding the replaced text, so you'll normally see "$(cmd args)".
In short, if you want to put a literal backquote into an argument string, you should either use single quotes:
lsof | grep '/file/path`s/'
or \-escape the backquote:
lsof | grep "/file/path\`s/"

Resources