Sed command from command line into script - bash

I want the string index.xml to be appended when I see something ending in /feed/ and starting with http://a.b.c
Using the command line I wrote, and works, this
echo "http://a.b.c/blabla/feed/" | sed -e 's#\(http://a.b.c/.*/feed/\)#\1index.xml#g'
I don't know how to transform this code so that it works in a script using -i and a file as parameter.
I tried the following but it works only if the searched string is on a line alone, while I need to transform also strings between other text. What's the correct code?
#!/bin/bash
sed -i 's#\("http://a.b.c/.*/feed/"\)#"\1index.xml"#g' $1

I think
#!/bin/bash
sed -i 's#\(http://a.b.c/.*/feed/\)#\1index.xml#g' "$1"
should work. I only removed the wrong double quotes in the command and added the missing ones around the $1.
If an input like http://aXbXc/ is not supposed to trigger the replacement, then you should also escape the dots.

Related

Changing a line of text with sed with special characters

The name in the title says it all. However, I'm absolutely the worst with the sed command. So I'm trying to edit the following file:
/var/www/html/phpMyAdmin/config.inc.php
I want to edit the line that says
$cfg['Servers'][$i]['AllowRoot'] = false;
into the following
$cfg['Servers'][$i]['AllowRoot'] = true;
It has so many special characters and whatnot and I have no prior knowledge of how sed works. So here's some commands I've tried to specifically edit that one line.
sed -i "/*.AllowRoot.*/\$cfg['Servers'][\$i]['AllowRoot'] = true;/" /var/www/html/phpMyAdmin/config.inc.php
sed -i "/*.AllowRoot.*/$cfg['Servers'][$i]['AllowRoot'] = true;/" /var/www/html/phpMyAdmin/config.inc.php
# this one finds the line successfully and prints it so I know it's got the right string:
sed -n '/AllowRoot/p' /var/www/html/phpMyAdmin/config.inc.php
sed -i "s/'AllowRoot|false'/'AllowRoot|true'/" /var/www/html/phpMyAdmin/config.inc.php
I have absolutely no idea what I'm doing and I'm not learning a whole lot besides the feeling that the last command splits up 'AllowRoot|false' makes sure that both must be present in the sentence to come back as a result. So to my logic, I thought changing the word false into true would make that happen, but nothing. The other commands return... bizarre results at best, one even emptying the file. Or that's one of the commands I had not written down here, I've lost track after 50 attempts. What is the solution here?
The [ and ] need to be escaped to match literal brackets, instead of inadvertently starting a bracket expression. This should work:
$ sed -i "/\$cfg\['Servers'\]\[\$i\]\['AllowRoot'\]/s/false/true/" /var/www/html/phpMyAdmin/config.inc.php
There is not many things to escape in sed. Main problem in your line is / which you have chosen as delimiter (most common, but not required). I suggest you use # and the following will work:
sed -i "s#$cfg['Servers'][$i]['AllowRoot'] = false;<br />#$cfg['Servers'][$i]['AllowRoot'] = true;<br />#g" input.txt
however you need to think about bash interpreter as well. $i and $cfg will be interpreted as variables. My suggestion is that when you want to match a string like this to put the sed expression in a text file like this:
cat allow_root_true.sed
s#['Servers'][]['AllowRoot'] = false;<br />#['Servers'][]['AllowRoot'] = true;<br />#g
and run the command using sed -f like this:
sed -i -f allow_root_true.sed input.txt
Warning -i will change the input file
sed can't do literal string matching which is why you need to escape so many characters (see Is it possible to escape regex metacharacters reliably with sed), but awk can:
$ awk -v str="\$cfg['Servers'][\$i]['AllowRoot']" 'index($0,str){sub(/false/,"true")} 1' file
//some text here
$cfg['Servers'][$i]['AllowRoot'] = true;<br />
//some more text here
Run code snippetHide resultsExpand snippet
In the above we only have to escape the $s to protect them from the shell since the string is enclosed in "s to allow it to include 's.

Delete double quotes in csv bash

I’m having the following issue:
I have the csv file with data inside looks like this:
“1,””name””,””surname””,””age””,””city”””
“2,””Peter””,””Parker””,””30””,””NY”””
“3,””marry””,””Jane””,””30””,””NY”””
Is it possible using bash to delete the first and the last double quote from each row and then first and last double quote from each field in it?
To get something like this:
1,”name”,”surname”,”age”,”NY”
3,”marry”,”Jane”,”30”,”NY”
I would be grateful for some hints. Thanks
To get you started:
echo '"1,""name"",""surname"",""age"",""city"""' | sed "s/\"\"/\"/g" | sed 's/^\"\(.*\)\"$/\1/'
OUPUT
You can take that, adjust it to run over a file, line by line (instead of the first echo and output into another file
Presuming your input looks like this:
"1,""name"",""surname"",""age"",""city"""
"2,""Peter"",""Parker"",""30"",""NY"""
"3,""marry"",""Jane"",""30"",""NY"""
Note the actual "'s not the ”” in your code:
You can then sed multiple things and chain them together e.g.
sed -e "s/\"\"\"/\"/g" -e "s/\"\"/\"/g" input.txt
This first replaces the triple quotes """, reducing them to double quotes "" and then reduces them further.
Final output:
"1,"name","surname","age","city"
"2,"Peter","Parker","30","NY"
"3,"marry","Jane","30","NY"
If you have special characters then simply replace them in the code e.g.:
$ cat input.txt
“1,””name””,””surname””,””age””,””city”””
“2,””Peter””,””Parker””,””30””,””NY”””
“3,””marry””,””Jane””,””30””,””NY”””
$ sed -e "s/\”\”\”/\”/g" -e "s/\”\”/\”/g" input.txt
“1,”name”,”surname”,”age”,”city”
“2,”Peter”,”Parker”,”30”,”NY”
“3,”marry”,”Jane”,”30”,”NY”
Though I think this input is a transpose error in your question.
Using sed:
sed 's/^"\(.*\)"$/\1/;s/"\+/"/g' file
The first substitution removes the outer double quote on the whole line.
The second substitution replaces the parameter quote to only one double quote.

Use a shell script to replace text with pwd

file.txt
...
<LOCAL_PATH_TO_REPO>/src/java/example.java
...
^A longer file but this pretty much explains what I am trying to do.
script.sh
dir=$(pwd)
# replace <LOCAL_PATH_TO_REPO> with dir
I tried using the sed command but it did not work for some reason. Any ideas on how to do this?
Your error means you have backslashes in the variable text.
The simplest solution is to change the delimiter to the one that does not occur in the variable text.
If there are no commas use a comma:
sed -i "s,LOCAL_PATH_TO_REPO,$PWD," file.yml
The -i flag introduces changes into the input file (works for GNU sed).

Create polymorphic bash without die trying. Sed replacing

I'm creating a bash script which in one point needs to modify itself in order to make persistent a change (only one line) of the script needs to change.
I know sed -i is what I need to do this. The problem is my sed command is replacing the line where the command is stored instead of the line I want. So I guess I need to include an exclusion while replacing. Let's check the snippet code stuff:
#!/bin/bash
echo "blah,blah,blah"
echo "more code here, not matters"
sed -i "s/#Awesome line to be replaced/#New line here/" "/path/to/my/script" 2> /dev/null
#Awesome line to be replaced
echo "blah,blah,blah, more code blah"
The problem here is the replaced line is not the line with only #Awesome line to be replaced. It is replaced the line where the sed command is.
This is a reduced example but the script is polymorphic and maybe the line numbers change, so it can't be based on line numbers. And there will be more sed commands like this... so I thought It could be nice to have some piece of text which always could be in the sed command lines in order to use it as excluding pattern, and yeah! that piece of text is /dev/null which always will be in sed command lines and never in the line which I want to replace.
How can achieve this using sed -i? Thanks in advance.
EDIT Forgot to say the order of appearance (offset) can't be used neither because of the polymorphic thing.
EDIT2 Beginning chars before #Awesome line to be replaced can't be used because they could change too. Sorry for who already answered based on this. Is complicated to write a polymorphic snippet considering all the possibilities.
This hack can work:
sed -i "s/#[A]wesome line to be replaced/#New line here/" "/path/to/my/script" 2> /dev/null
I think it is self-explanatory, why it will not match the sed line itself.
Anchor your expression by starting your sed line with :
sed -i "s/^$'\t'*#Awesome (rest of command goes here)
This will make sure sed only matches if the text found is at the beginning of the line with zero or more tabs, and will not match the line with the actual sed command.

How to append to specific lines in a flat file using shell script

I have a flat file that contains something like this:
11|30646|654387|020751520
11|23861|876521|018277154
11|30645|765418|016658304
Using shell script, I would like to append a string to certain lines in this file, if those lines contain a specific string.
For example, in the above file, for lines containing 23861, I would like to append a string "Processed" at the end, so that the file becomes:
11|30646|654387|020751520
11|23861|876521|018277154|Processed
11|30645|765418|016658304
I could use sed to append the string to all lines in the file, but how do I do it for specific lines ?
I'd do it this way
sed '/\|23861\|/{s/$/|Something/;}' file
This is similar to Marcelo's answer but doesn't require extended expressions and is, I think, a little cleaner.
First, match lines having 23861 between pipes
/\|23861\|/
Then, on those lines, replace the end-of-line with the string |Something
{s/$/|Something/;}
If you want to do more than one of these you could simply list them
sed '/\|23861\|/{s/$/|Something/;};/\|30645\|/{s/$/|SomethingElse/;}' file
Use the following awk-script:
$ awk '/23861/ { $0=$0 "|Processed" } {print}' input
11|30646|654387|020751520
11|23861|876521|018277154|Processed
11|30645|765418|016658304
or, using sed:
$ sed 's/\(.*23861.*$\)/\1|Processed/' input
11|30646|654387|020751520
11|23861|876521|018277154|Processed
11|30645|765418|016658304
Use the substitution command:
sed -i~ -E 's/(\|23861\|.*)/\1|Processed/' flat.file
(Note: the -i~ performs the substitution in-place. Just leave it out if you don't want to modify the original file.)
You can use the shell
while read -r line
do
case "$line" in
*23681*) line="$line|Processed";;
esac
echo "$line"
done < file > tempo && mv tempo file
sed is just a stream version of ed, which has a similar command set but was designed to edit files in place (allegedly interactively, but you wouldn't want to use it that way unless all you had was one of these). Something like
field_2_value=23861
appended_text='|processed'
line_match_regex="^[^|]*|$field_2_value|"
ed "$file" <<EOF
g/$line_match_regex/s/$/$appended_text/
wq
EOF
should get you there.
Note that the $ in .../s/$/... is not expanded by the shell, as are $line_match_regex and $appended_text, because there's no such thing as $/ - instead it's passed through as-is to ed, which interprets it as text to substitute ($ being regex-speak for "end of line").
The syntax to do the same job in sed, should you ever want to do this to a stream rather than a file in place, is very similar except that you don't need the leading g before the regex address:
sed -e "/$line_match_regex/s/$/$appended_text/" "$input_file" >"$output_file"
You need to be sure that the values you put in field_2_value and appended_text never contain slashes, because ed's g and s commands use those for delimiters.
If they might do, and you're using bash or some other shell that allows ${name//search/replace} parameter expansion syntax, you could fix them up on the fly by substituting \/ for every / during expansion of those variables. Because bash also uses / as a substitution delimiter and also uses \ as a character escape, this ends up looking horrible:
appended_text='|n/a'
ed "$file" <<EOF
g/${line_match_regex//\//\\/}/s/$/${appended_text//\//\\/}/
wq
EOF
but it does work. Nnote that both ed and sed require a trailing / after the replacement text in s/search/replace/ while bash's ${name//search/replace} syntax doesn't.

Resources