replace all '/' with '\/' in bash/shell script - bash

This might be very simple but I am stuck at getting this done in shell/bash.
I have input like "a/b/c/d" and I want to replace all '/' with '\/' and the output would be 'a/b/c/d'
another example is 12.12.12.12/32 >>> 12.12.12.12\/32
Any help would be appreciated.

You can use bash's parameter expansion:
$ input="a/b/c/d"
$ echo "${input//\//\\/}"
a\/b\/c\/d
Given a variable input, ${input//xxx/yyy} yields the content of input with every xxx replaced with yyy. Here xxx is \/ (/ must be escaped to not be mixed up with the next /) and yyy is \\/ (\/ with \ being escaped).

Using bash only
var='a/b/c/d'
echo "${var//\//\\/}"

This would do:
echo "12.12.12.12/32" |sed 's,/,\\/,g'
Output:
12.12.12.12\/32
In such scenarios, use a delimiter other than /, as i used , in the above example. You can use for example: #,?....etc

Depending on how you access the text or strings you want to make the replacement in, something like this might work. You have to escape both / and \ inside the sed command.
var='a/b/c/d'
echo "$var" | sed 's/\//\\\//g'

Related

Issue when using sed in combination with read

I am having a problem with sed. Basically, I want to insert some text after a match a small piece of Java code after a match. It seems to be somehow interpreted as something else and ends up failing.
Consider the following basic example that does what I want:
match="string_I_want_to_match"
str_i_want_above="str I want above"
echo $match | sed -e "/$match/i \\
$str_i_want_above"
outputs what I want:
xyzt
string_I_want_to_match
However, if I use read to create a multiline string, it fails with an obscure error. Consider the following example:
match="string_I_want_to_match"
read -r -d '' str_i_want_above <<- 'EOF'
> I
> Want
> This
> Above the match
EOF
echo $match | sed -e "/$match/i \\
$str_i_want_above"
I expect
I
Want
This
Above the match
string_I_want_to_match
but instead I get
sed: 3: "/string_I_want_to_match ...": invalid command code W
It's somehow failing when trying to interpret the second line. I have isolated this to be a problem with read but if I'm wrong, I'd like to understand why and to fix this.
I'm using BSD sed on mac 12.6. I would like to achieve this with sed and read because I need to do in-place replacing and this is going to be a larger script where I need to do several in-place insertions of multiline strings
You need to insert a \ before the line breaks in replacement, so you may use:
match="string_I_want_to_match"
echo "$match" | sed "/$match/i \\
> ${str_i_want_above//$'\n'/\\$'\n'}
> "
I
Want
This
Above the match
string_I_want_to_match
Here:
${str_i_want_above//$'\n'/\\$'\n'}: Inserts \\ before each line break
Code Demo

Append text to top of file using sed doesn't work for variable whose content has "/" [duplicate]

This question already has answers here:
Using different delimiters in sed commands and range addresses
(3 answers)
Closed 1 year ago.
I have a Visual Studio project, which is developed locally. Code files have to be deployed to a remote server. The only problem is the URLs they contain, which are hard-coded.
The project contains URLs such as ?page=one. For the link to be valid on the server, it must be /page/one .
I've decided to replace all URLs in my code files with sed before deployment, but I'm stuck on slashes.
I know this is not a pretty solution, but it's simple and would save me a lot of time. The total number of strings I have to replace is fewer than 10. A total number of files which have to be checked is ~30.
An example describing my situation is below:
The command I'm using:
sed -f replace.txt < a.txt > b.txt
replace.txt which contains all the strings:
s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g
a.txt:
?page=one&
?page=two&
?page=three&
Content of b.txt after I run my sed command:
pageone
pagetwo
pagethree
What I want b.txt to contain:
/page/one
/page/two
/page/three
The easiest way would be to use a different delimiter in your search/replace lines, e.g.:
s:?page=one&:pageone:g
You can use any character as a delimiter that's not part of either string. Or, you could escape it with a backslash:
s/\//foo/
Which would replace / with foo. You'd want to use the escaped backslash in cases where you don't know what characters might occur in the replacement strings (if they are shell variables, for example).
The s command can use any character as a delimiter; whatever character comes after the s is used. I was brought up to use a #. Like so:
s#?page=one&#/page/one#g
A very useful but lesser-known fact about sed is that the familiar s/foo/bar/ command can use any punctuation, not only slashes. A common alternative is s#foo#bar#, from which it becomes obvious how to solve your problem.
add \ before special characters:
s/\?page=one&/page\/one\//g
etc.
In a system I am developing, the string to be replaced by sed is input text from a user which is stored in a variable and passed to sed.
As noted earlier on this post, if the string contained within the sed command block contains the actual delimiter used by sed - then sed terminates on syntax error. Consider the following example:
This works:
$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345
This breaks:
$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'
Replacing the default delimiter is not a robust solution in my case as I did not want to limit the user from entering specific characters used by sed as the delimiter (e.g. "/").
However, escaping any occurrences of the delimiter in the input string would solve the problem.
Consider the below solution of systematically escaping the delimiter character in the input string before having it parsed by sed.
Such escaping can be implemented as a replacement using sed itself, this replacement is safe even if the input string contains the delimiter - this is since the input string is not part of the sed command block:
$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6
I have converted this to a function to be used by various scripts:
escapeForwardSlashes() {
# Validate parameters
if [ -z "$1" ]
then
echo -e "Error - no parameter specified!"
return 1
fi
# Perform replacement
echo ${1} | sed -e "s#/#\\\/#g"
return 0
}
this line should work for your 3 examples:
sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
I used -r to save some escaping .
the line should be generic for your one, two three case. you don't have to do the sub 3 times
test with your example (a.txt):
kent$ echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
replace.txt should be
s/?page=/\/page\//g
s/&//g
please see this article
http://netjunky.net/sed-replace-path-with-slash-separators/
Just using | instead of /
Great answer from Anonymous. \ solved my problem when I tried to escape quotes in HTML strings.
So if you use sed to return some HTML templates (on a server), use double backslash instead of single:
var htmlTemplate = "<div style=\\"color:green;\\"></div>";
A simplier alternative is using AWK as on this answer:
awk '$0="prefix"$0' file > new_file
You may use an alternative regex delimiter as a search pattern by backs lashing it:
sed '\,{some_path},d'
For the s command:
sed 's,{some_path},{other_path},'

How to replace numbers by using sed?

I wanted to change #232-12-3424 into these symbols #%%%-%%-%%% but still having same numbers whenever I run it.
Here's my code I tried but didn't worked out.
s/#[0-9]{3}-[0-9]{2}-[0-9]{4}*/#%%%-%%-%%%%/;
Two things :
putting \ before '{' to escape
Putting a quantifiable token before * (ex: .) or removing it .
Please note if you are using '.*' it will replace whole string (Please check following
example.
cat boo
#232-12-3424
#456-23-7896 some text
cat boo | sed -e 's/#[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}/#%%%-%%-%%%%/'
#%%%-%%-%%%%
#%%%-%%-%%%% some text
cat boo | sed -e 's/#[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}.*/#%%%-%%-%%%%/'
#%%%-%%-%%%%
#%%%-%%-%%%%

Unexplained line break

I'm very sorry if someone already have ask this question or something near it, but I did not found anything close to it, but may be it's because of my weakness in coding.
I have bash this script:
...
...
## Read n line in vmlist
VMTORESTORE=$(sed -n "$yn p" ./vmlist)
## Replace " " between names by "\ "
VMTORESTORE="$(echo "$VMTORESTORE" | sed 's/ /\\ /g' )"
## Test variable
echo $VMTORESTORE
## Run Command
ls -1 /vmfs/volumes/BACKUP_SAN/$VMTORESTORE | sed 's/ /\\ /g'
This is the result:
Save\ Camera
ls: /vmfs/volumes/BACKUP_SAN/Save: No such file or
directory
Camera:
I don't understand why the echo gave the good result whereas the command insert a line break between Save\ and Camera.
thanks by advance for your help.
Proc
it is a good idea to quote the variables as in:
ls -1 "/vmfs/volumes/BACKUP_SAN/$VMTORESTORE"
Take this as a good practice and update the script wherever needed.
This is happening because \ is an escape character in bash. So shouldnt your path consists of / rather than \ to define the location save/camera. Also globbing happens when you are using commands without " " so use the address in " ".
Thanks you all, I did not expect a solution that easy.
You were right, the double quotes were needed.
But in my cas this was not enough.
The path to the searched folder was:
"/vmfs/volume/BACKUP_SAN/Save Camera/"
but usually in Linux to reach this kind of folder I need to put \ before spaces like that:
"/vmfs/volume/BACKUP_SAN/Save\ Camera/"
That's why I replaced in my script all " " with "\ "
But is seems in a bash script this is not needed so this works like a charm:
...
...
## Read n line in vmlist
VMTORESTORE=$(sed -n "$yn p" ./vmlist)
## Run Command
ls -1 "/vmfs/volumes/BACKUP_SAN/$VMTORESTORE"
I searched the complication whereas it was this simple.
Thank you all for your help.

In a bash script, how do I sanitize user input?

I'm looking for the best way to take a simple input:
echo -n "Enter a string here: "
read -e STRING
and clean it up by removing non-alphanumeric characters, lower(case), and replacing spaces with underscores.
Does order matter? Is tr the best / only way to go about this?
As dj_segfault points out, the shell can do most of this for you. Looks like you'll have to fall back on something external for lower-casing the string, though. For this you have many options, like the perl one-liners above, etc., but I think tr is probably the simplest.
# first, strip underscores
CLEAN=${STRING//_/}
# next, replace spaces with underscores
CLEAN=${CLEAN// /_}
# now, clean out anything that's not alphanumeric or an underscore
CLEAN=${CLEAN//[^a-zA-Z0-9_]/}
# finally, lowercase with TR
CLEAN=`echo -n $CLEAN | tr A-Z a-z`
The order here is somewhat important. We want to get rid of underscores, plus replace spaces with underscores, so we have to be sure to strip underscores first. By waiting to pass things to tr until the end, we know we have only alphanumeric and underscores, and we can be sure we have no spaces, so we don't have to worry about special characters being interpreted by the shell.
Bash can do this all on it's own, thank you very much. If you look at the section of the man page on Parameter Expansion, you'll see that that bash has built-in substitutions, substring, trim, rtrim, etc.
To eliminate all non-alphanumeric characters, do
CLEANSTRING=${STRING//[^a-zA-Z0-9]/}
That's Occam's razor. No need to launch another process.
For Bash >= 4.0:
CLEAN="${STRING//_/}" && \
CLEAN="${CLEAN// /_}" && \
CLEAN="${CLEAN//[^a-zA-Z0-9]/}" && \
CLEAN="${CLEAN,,}"
This is especially useful for creating container names programmatically using docker/podman. However, in this case you'll also want to remove the underscores:
# Sanitize $STRING for a container name
CLEAN="${STRING//[^a-zA-Z0-9]/}" && \
CLEAN="${CLEAN,,}"
After a bit of looking around it seems tr is indeed the simplest way:
export CLEANSTRING="`echo -n "${STRING}" | tr -cd '[:alnum:] [:space:]' | tr '[:space:]' '-' | tr '[:upper:]' '[:lower:]'`"
Occam's razor, I suppose.
You could run it through perl.
export CLEANSTRING=$(perl -e 'print join( q//, map { s/\\s+/_/g; lc } split /[^\\s\\w]+/, \$ENV{STRING} )')
I'm using ksh-style subshell here, I'm not totally sure that it works in bash.
That's the nice thing about shell, is that you can use perl, awk, sed, grep....

Resources