How to escape a character in a variable? [duplicate] - shell

This question already has answers here:
Escape a string for a sed replace pattern
(17 answers)
Closed 1 year ago.
I have a script that passes a variable into a sed command like this:
sed "s-\t-&${SUBDIRECTORY}/-"
But if the variable contains - (dash), then the sed command throws an error.
So this script:
VARIABLE="test-variable"
sed "s-\t-&${VARIABLE}/-"
Results in this error:
sed: 1: "s-\t-&test-variable/-": bad flag in substitute command: 'v'
I have not been able to find any answers to this issue; it works fine without the -.
How can I fix this?

Use a shell parameter expansion that escapes each instance of -:
sed "s-\t-&${VARIABLE//-/\\-}/-"
In the Bash manual, under Shell Parameter Expansion:
${parameter/pattern/string}
The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. [...] If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. [...]

Proper escaping is a fairly difficult problem in the shell, but you could do something like:
$ variable="test-variable"
$ printf '\t\n' | v="$variable" perl -pe 's-\t-$ENV{v}-'
test-variable

Related

How to use parameter expansion correctly in bash [duplicate]

This question already has answers here:
Stripping prefixes and suffixes from shell words matching a pattern
(2 answers)
Difference between ${} and $() in Bash [duplicate]
(3 answers)
Closed 1 year ago.
I have a string with the structure task_name-student_name and I want to split it into two variables:
task: containing the chunk before the -
student: containing the chunk after the -
I can get this to work with sed:
string="task_name-student_name"
student=$(echo "$string" | sed "s/.*-//")
task=$(echo "$string" | sed "s/-[^-]*$//")
However, VS Code suggests "See if you can use $(variable//search/replace) instead".
So I have two questions:
Why would $(variable//search/replace) be better
How do I get the parameter expansion to work without it being interpreted as a command?
When I try
echo $("$string"//-[^-]*$//)
or
echo $(echo $("$string"//-[^-]*$//))
I get this output:
bash: task_name-student_name//-[^-]*$//: No such file or directory
Thanks in advance!
First: for variable expansion, you want curly braces instead of parentheses. $(something) will execute something as a command; ${something} will expand something as a variable. And just for completeness, $((something)) will evaluate something as an arithmetic expression (integers only, no floating point).
As for replacing the sed with a variable expansion: I wouldn't use $(variable//search/replace} for this; there are more appropriate modifications. ${variable#pattern} will remove the shortest possible match of pattern from the beginning of the variable's value, so use that with the pattern *- to remove through the first "-":
student=${string#*-}
Similarly, ${variable%pattern} will remove from the end of the variable's value, so you can use this with the pattern -* to remove from the dash to the end:
task=${string%-*}
Note that the patterns used here are "glob" expressions (like filename wildcards), not regular expressions like sed uses; they're just different enough to be confusing. Also, the way I've written these assumes there's exactly one "-" in the string; if there's a possibility some student will have a hyphenated name or something like that, you may need to modify them.
There are lots more modifications you can do in a parameter expansion; see the bash hacker's wiki on the subject. Some of these modifications will work in other shells besides bash; the # and % modifiers (and the "greedy" versions, ## and %%) will work in any shell that conforms to the POSIX standard.

How to print string before specific word in bash?

I want to learn how to extract only the Kernel Version from this specific output:
3.10.0-1127.18.2.el7.x86_64Repository rhel-7-server-optional-rpms is listed more than once in the configuration
This is the output that I am aiming for: 3.10.0-1127.18.2.el7.x86_64
bash:
var="3.10.0-1127.18.2.el7.x86_64Repository rhel-7-server-optional-rpms"
echo "${var%%Repository*}"
See 3.5.3 Shell Parameter Expansion in the manual.
There are several ways.
A "simple" is using sed with a regex to replace the part that you want to strip.
Ex:
echo "3.10.0-1127.18.2.el7.x86_64Repository rhel-7-server-optional-rpms" | sed -E "s/Repository.*//"
3.10.0-1127.18.2.el7.x86_64
To explain the sed command used : sed -E "s/Repository.*//" :
E` is for extended regular expression.
And sed syntax substitution is :
s/regexp/replacement/
Attempt to match regexp against the pattern space. If successful,
replace that portion matched with replacement
Here we replace the string found by nothing.

Replacing with single quote using sed [duplicate]

This question already has answers here:
How to escape single quote in sed?
(9 answers)
Closed 2 years ago.
I want to replace a set of characters with ' using sed.
This post suggest:
With single quotes around the argument (sed 's/…/…/'), use '\'' to put a single quote in the replacement text.
So, I tried following:
echo 'abcd' | sed 's/[abcd]/\'/g'
But it simply ends up expecting more input:
anir#DESKTOP-4856511:~$ echo 'abcd' | sed 's/[abcd]/\'/g'
>
>
>
> ^C
When I copy pasted echo 'abcd' | sed 's/[abcd]/\'/g' in .sh file and ran, it gave me following error:
anir#DESKTOP-4856511:~/Mahesha999/delete$ ./trysed.sh
./trysed.sh: line 1: unexpected EOF while looking for matching `''
./trysed.sh: line 2: syntax error: unexpected end of file
What the right way to do this? Is it impossible to escape single quote inside single quoted string (and I have to use double quotes only as explained here)?
As the post says:
With single quotes around the argument (sed 's/…/…/'), use '\'' to put a single quote in the replacement text.
So, using your example, you would do:
echo 'abcd' | sed 's/[abcd]/'\''/g'
If you want to replace with just one single quote:
echo 'abcd' | sed 's/[abcd][abcd]*/'\''/g'
The shell does not allow single quotes inside a single quoted string. What the code above does is create three strings (which are not separated by anything):
single-quoted string: 's/[abcd]/'
unquoted string containing just an escaped single-quote: \'
single-quoted string: '/g'
The shell then expands them and because they are not separated, they effectively become joined into a single string.
sed sees: s/[abcd]/'/g

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

Escaping forward slashes in sed command [duplicate]

This question already has answers here:
Escape a string for a sed replace pattern
(17 answers)
sed search and replace strings containing / [duplicate]
(2 answers)
Closed 3 years ago.
With Bash and SED I'm trying to replace two strings in a js file with URL's.
The two urls that should be inserted is input params when I run the .sh script.
./deploy.sh https://hostname.com/a/index.html https://hostname2.com/test
However to make this usable in my sed command I have to escape all forward slashes with: \\ ?
./deploy.sh https:\\/\\/hostname.com\\/a\\/index.html https:\\/\\/hostname2.com\\/test
If they are escaped this SED command works on Mac OSX Sierra
APP_URL=$1
API_URL=$2
sed "s/tempAppUrl/$APP_URL/g;s/tempApiUrl/$API_URL/g" index.src.js > index.js
Now I don't want to insert escaped urls as params, I want the script it self to escape the forward slashes.
This is what I've tried:
APP_URL=$1
API_URL=$2
ESC_APP_URL=(${APP_URL//\//'\\/'})
ESC_API_URL=(${API_URL//\//'\\/'})
echo 'Escaped URLS'
echo $ESC_APP_URL
#Echos result: https:\\/\\/hostname.com\\/a\\/index.html
echo $ESC_API_URL
#Echos result: https:\\/\\/hostname2.com\\/test
echo "Inserting app-URL and api-URL before dist"
sed "s/tempAppUrl/$ESC_APP_URL/g;s/tempApiUrl/$ESC_API_URL/g" index.src.js > index.js
The params looks the same but in this case the SED throws a error
sed: 1: "s/tempAppUrl/https:\\/\ ...": bad flag in substitute command: '\'
Could anyone tell me the difference here? The Strings looks the same but gives different results.
I suggest to replace
sed "s/regex/replace/" file
with
sed "s|regex|replace|" file
if your sed supports it. Then it is no longer necessary to escape the slashes.
The character directly after the s determines which character is the separator, which must appear three times in the s command.

Resources