How can I combine sed commands to a shell script [duplicate] - linux

This question already has answers here:
Combining two sed commands
(2 answers)
Closed 7 years ago.
I Have to Operate the following sed commands over a file to remove some lines in that file. How can I make this a shell scipt with the file name as a variable. Or is there any simple way to do this as a shell script
sed -i '/^Total/d' delhi222517.txt
sed -i '/^CBSE/d' delhi222517.txt
sed -i '/^Keyword wise/d' delhi222517.txt
sed -i '/^wise/d' delhi222517.txt
sed -i '/^Select A/d' delhi222517.txt
sed -i '/^Enter A/d' delhi222517.txt
sed -i '/^(Keyword/d' delhi222517.txt
sed -i '/^State Name/d' delhi222517.txt
sed -i '/^SNo/d' delhi222517.txt
sed -i '/^Disclaimer/d' delhi222517.txt
sed -i '/^provided/d' delhi222517.txt
sed -i '/^at$/d' delhi222517.txt
sed -i '/^Designed/d' delhi222517.txt
sed -i '/^National/d' delhi222517.txt
sed -i '/^$/d' delhi222517.txt
sed -i '/^\t$/d' delhi222517.txt
sed -i '/^\s$/d' delhi222517.txt
sed -i '/^ /d' delhi222517.txt
sed -i '/^ /d' delhi222517.txt
sed -i 's/^\([0-9]\)/--\1/g' delhi222517.txt

The variable thing is easy:
F=delhi222517.txt
sed -i '/^Total/d' "$F"
...
Or if you want to pass the name of the file as argument to your script:
F="$1"
sed -i '/^Total/d' "$F"
...
But it is better to use the sed options to call it only once. You can use:
sed -i \
-e '/^Total/d' \
-e '/^CBSE/d' \
-e '/^Keyword wise/d' \
... \
delhi222517.txt
Or you can write a file with the full script:
sed -i -f script.sed delhi222517.txt
Or if you feel geek enough, you can use the standard input:
sed -i -f - delhi222517.txt << EOF
/^Total/d
/^CBSE/d
/^Keyword wise/d
...
EOF

On the Command Line
On the command line, you can separate sed commands with semi-colons or with multiple expression arguments. As generic examples:
# Using Semi-Colons
sed -i 's/foo/bar/; s/baz/quux/' infile
# Using Multiple Expressions
sed -i -e 's/foo/bar/' -e 's/baz/quux/' infile
Write a Full-Fledged Sed Script
In general, though, if your commands are numerous, stop using one-liners and build a full-fledged sed script. For example, you could create a file named /tmp/foo.sed containing the following commands from your question:
/^Total/d
/^CBSE/d
/^Keyword wise/d
/^wise/d
/^Select A/d
/^Enter A/d
/^(Keyword/d
/^State Name/d
/^SNo/d
/^Disclaimer/d
/^provided/d
/^at$/d
/^Designed/d
/^National/d
/^$/d
/^\t$/d
/^\s$/d
/^ /d
/^ /d
s/^\([0-9]\)/--\1/g
Then invoke your commands all at once. For example, using GNU sed:
infile='delhi222517.txt'
script='/tmp/foo.sed'
sed --in-place --file="$script" "$infile"

Well you can put them in a a shell script like this:
#!/bin/bash
# some sanity checks
file="$1"
sed -i '/^Total/d' "$file"
sed -i '/^CBSE/d' "$file"
sed -i '/^Keyword wise/d' "$file"
sed -i '/^wise/d' "$file"
#.. more sed commands
btw your various sed commands can be combined into 1 or fewer sed command using reges like:
sed -r -i '/^(Total|CBSE)/d' "$file"

If your script is not going to run any program other than sed your file, then this may be the cleanest way to set it up:
#!/bin/sed -f # <- run the file passed to the program from the command-line
/^Total/Id # /I is the case-insensitive flag, replacing sed -i
/^CBSE/Id
/^Keyword wise/Id
/^wise/Id
/^Select A/Id
/^Enter A/Id
...
Make the above script executable, and then just pass it the filename that you wish to convert:
./mysedscript delhi222517.txt

Using awk you can do all in go:
file=delhi222517.txt
awk '!/^(Total|CBSE|Keyword wise|wise)/' "$file"

Related

How to apply my sed command to some lines of all my files?

I've 95 files that looks like :
2019-10-29-18-00/dev/xx;512.00;0.4;/var/x/xx/xxx
2019-10-29-18-00/dev/xx;512.00;0.68;/xx
2019-10-29-18-00/dev/xx;512.00;1.84;/xx/xx/xx
2019-10-29-18-00/dev/xx;512.00;80.08;/opt/xx/x
2019-10-29-18-00/dev/xx;20480.00;83.44;/var/x/x
2019-10-29-18-00/dev/xx;3584.00;840.43;/var/xx/x
2019-10-30-00-00/dev/xx;2048.00;411.59;/
2019-10-30-00-00/dev/xx;7168.00;6168.09;/usr
2019-10-30-00-00/dev/xx;3072.00;1036.1;/var
2019-10-30-00-00/dev/xx;5120.00;348.72;/tmp
2019-10-30-00-00/dev/xx;20480.00;2033.19;/home
2019-10-30-12-00;/dev/xx;5120.00;348.72;/tmp
2019-10-30-12-00;/dev/hd1;20480.00;2037.62;/home
2019-10-30-12-00;/dev/xx;512.00;0.43;/xx
2019-10-30-12-00;/dev/xx;3584.00;794.39;/xx
2019-10-30-12-00;/dev/xx;512.00;0.4;/var/xx/xx/xx
2019-10-30-12-00;/dev/xx;512.00;0.68;/xx
2019-10-30-12-00;/dev/xx;512.00;1.84;/var/xx/xx
2019-10-30-12-00;/dev/xx;512.00;80.08;/opt/xx/x
2019-10-30-12-00;/dev/xx;20480.00;83.44;/var/xx/xx
2019-10-30-12-00;/dev/x;3584.00;840.43;/var/xx/xx
For some lines I've 2019-10-29-18-00/dev and for some other lines, I've 2019-10-30-12-00;/dev/
I want to add the ; before the /dev/ where it is missing, so for that I use this sed command :
sed 's/\/dev/\;\/dev/'
But How I can apply this command for each lines where the ; is missing ? I try this :
for i in $(cat /home/xxx/xxx/xxx/*.txt | grep -e "00/dev/")
do
sed 's/\/dev/\;\/dev/' $i > $i
done
But it doesn't work... Can you help me ?
Could you please try following with GNU awkif you are ok with it.
awk -i inplace '/00\/dev\//{gsub(/00\/dev\//,"/00;/dev/")} 1' *.txt
sed solution: Tested with GNU sed for few files and it worked fine.
sed -i.bak '/00\/dev/s/00\/dev/00\;\/dev/g' *.txt
This might work for you (GNU sed & parallel):
parallel -q sed -i 's#;*/dev#;/dev#' ::: *.txt
or if you prefer:
sed -i 's#;*/dev#;/dev#' *.txt
Ignore lines with ;/dev.
sed '/;\/dev/{p;d}; s^/dev^;/dev^'
The /;\/dev/ check if the line has ;/dev. If it has ;/dev do: p - print the current line and d - start from the beginning.
You can use any character with s command in sed. Also, there is no need in escaping \;, just ;.
How I can apply this command for each lines where the ; is missing ? I try this
Don't edit the same file redirecting to the same file $i > $i. Think about it. How can you re-write and read from the same file at the same time? You can't, the resulting file will be in most cases empty, as the > $i will "execute" first making the file empty, then sed $i will start running and it will read an empty file. Use a temporary file sed ... "$i" > temp.txt; mv temp.txt "$i" or use gnu extension -i sed option to edit in place.
What you want to do really is:
grep -l '00/dev/' /home/xxx/xxx/xxx/*.txt |
xargs -n1 sed -i '/;\/dev/{p;d}; s^/dev^;/dev^'
grep -l prints list of files that match the pattern, then xargs for each single one -n1 of the files executes sed which -i edits files in place.
grep for filtering can be eliminated in your case, we can accomplish the task with a single sed command:
for f in $(cat /home/xxx/xxx/xxx/*.txt)
do
[[ -f "$f" ]] && sed -Ei '/00\/dev/ s/([^;])(\/dev)/\1;\2/' "$f"
done
The easiest way would be to adjust your regex so that it's looking a bit wider than '/dev/', e.g.
sed -i -E 's|([0-9])/dev|\1;/dev|'
(note that I'm taking advantage of sed's flexible approach to delimiters on substitute. Also, -E changes the group syntax)
Alternatively, sed lets you filter which lines it handles:
sed -i '/[0-9]\/dev/ s/\/dev/;/dev/'
This uses the same substitution you already have but only applied on lines that match the filter regex

how to find/replace string in file

I'm trying to find in file this string:
"cPHulk":{"BruteForce":3,"Login":3,"*":3}
and replace it with this string:
"cPHulk":{"*":"1","Login":"1","BruteForce":"1"}
I'm using sed to do this but I struggle a lot. My sed command is as follow:
sed -i -e 's/"cPHulk":{"BruteForce":3,"Login":3,"*":3}/"cPHulk":{"*":"1","Login":"1","BruteForce":"1"}/g' /var/cpanel/icontact_event_importance.json
EDIT:
The correct sed formula:
sed -i -e 's/"cPHulk":{"BruteForce":3,"Login":3,"\*":3}/"cPHulk":{"\*":"1","Login":"1","BruteForce":"1"}/g' /var/cpanel/icontact_event_importance.json
I found on some *nix you must provide a blank as the suffix to get it make an in-place replacement:
sed -i '' -e 's/"cPHulk":{"BruteForce":3,"Login":3,"*":3}/"cPHulk":{"*":"1","Login":"1","BruteForce":"1"}/g' /var/cpanel/icontact_event_importance.json
Note the '' after -i

How to replace all occurrences in 1 file with sed?

I need to replace all occurrences and write back to the same file
I tried:
sed 's/one/two/g' file.txt
this print out but does not write to file
I also tried
sed 's/one/two/g' file.txt>file.txt
This results in empty file
sed -i 's/one/two/g' file.txt
gives error: sed: 1: "file.txt": invalid command code f
Any idea?
For Mac: Use -i.bak to add a backup file
sed -i.bak 's/one/two/g' file.txt
Or
sed -i '' 's/one/two/g' file.txt
For Linux:
Use sed -i on to do infile substitution
sed -i 's/one/two/g' file.txt
You can also do something like below using a tmp file:
sed 's/one/two/g' file.txt > tmp.txt && mv tmp.txt file.txt

Redirecting and writing in the same file

Hi i have a script which replaces the certain occurrences in the .sql files and after that writes it in the some new file.So,i m here unnecessarily creating extra files.Is there anyway by which i can write in the same file.
Below is the part of the script:
sed "s/v1/$value1/g" Save.sql >> CreateViewFinal1.sql
sed "s/v2/$value2/g" CreateViewFinal1.sql >> CreateViewFinal2.sql
sed "s/v3/$value3/g" CreateViewFinal2.sql >> CreateViewFinal3.sql
sed "s/v4/$value4/g" CreateViewFinal3.sql >> CreateViewFinal4.sql
sed "s/v5/$value5/g" CreateViewFinal4.sql >> CreateViewFinal5.sql
sed "s/v6/$value6/g" CreateViewFinal5.sql >> CreateViewFinal6.sql
sed "s/v7/$value7/g" CreateViewFinal6.sql >> CreateViewFinal7.sql
sed "s/v8/$value8/g" CreateViewFinal7.sql >> CreateViewFinal8.sql
sed "s/v9/$value9/g" CreateViewFinal8.sql >> CreateViewFinal9.sql
sed "s/a1/$value10/g" CreateViewFinal9.sql >> CreateViewFinal10.sql
sed "s/b1/$value11/g" CreateViewFinal10.sql >> CreateViewFinal11.sql
sed "s/c1/$value12/g" CreateViewFinal11.sql >> CreateViewFinal12.sql
sqlplus -S -L cimkroger/cimkroger#orcl #CreateViewFinal12.sql
Thanks in advance.
You can sed's inline editing and can avoid multiple sed commands with -e switch like this:
sed -i.bak -e "s/v1/$value1/g" -e "s/v2/$value2/g" -e "s/v3/$value3/g" Save.sql
Yes.
You can change a file directly with the -i option of sed.
Hence, sed -i .... file will replace something in the same file.
Moreover, instead of so many sed different lines, you can do multiple sed actions with the -e option. So instead of:
sed "s/v1/$value1/g" Save.sql >> CreateViewFinal1.sql
sed "s/v2/$value2/g" CreateViewFinal1.sql >> CreateViewFinal2.sql
sed "s/v3/$value3/g" CreateViewFinal2.sql >> CreateViewFinal3.sql
You can do
sed -i -e "s/v1/$value1/g" -e "s/v2/$value2/g" -e "s/v3/$value3/g" Save.sql
and so on.
Example
$ cat file
hello you
$ sed -i -e 's/hello/bye/g' -e 's/you/me/g' file
$ cat file
bye me

Find a string and add multiple lined string saved in variable before

I have been trying quite a few ways with no luck. I have a file named test.txt that has some lorem ipsum and the text [staging: production] I simply want to add a few lines that I have saved in a variable in before it.
If you could explain where I have gone wrong with any of the below it would be much appreciated!
#!/bin/bash
test="lala\
kjdsh"
sed '/^#$/{N; /[staging: production]/ i \
<Location /cgis> \
</Location>\
}' ./test.txt
sed -i -e 's/\[staging\: production\]/\$test/g' ./test.txt
#sed -i 's/Lorem/beautiful/g' test.txt
#awk -v data=$test '{A[NR]=$0}/\[staging\: production\]/{ print data }' test.txt > testfile.txt
#read -a text <<<$(cat test.txt)
#echo ${#text[#]}
#for i in ${text[#]};
#do
# echo -n $i;
# sleep .2;
#done
#ed -s test.txt <<< $'/\[staging\: production\]/s/lalalala/g\nw'
#awk -v data=$test '/\(/\[staging\: production\]\)/ { print data }' test.txt > testfile.txt
# && mv testfile.txt test.txt
#sed -i -e '/\(\[staging\: production\]\)/r/$test\1/g' test.txt
#sed "/\(\[staging\: production\]\)/s//$test\1/g" test.txt
sed -i -e 's/\[staging\: production\]/\$test/g' ./test.txt
won't work because inside singe quotes BASH will not expand \$test.
Therefore you don't need to escape the $.
If you want to substitute with the contents of the variable $test do:
sed -i -e 's/\[staging: production\]/'$test'/g' ./test.txt
You also do not need to escape :
To insert before your pattern works for me this way:
sed -i -e '/\[staging: production\]/ i '$test'' ./test.txt
However to preserve the linebreak inside the variable I needed to define:
test="lala\nkjdsh"
Please note the \n to encode the linebreak.
Try it in perl, it seems to work fine:
perl -pe '{$rep="what\nnow"; s/(\[foo foo2\])/$rep$1/}' file
This might work for you (GNU sed):
test="lala\\
kjdsh"
sed '/\[staging: production\]/i\'"$test" test.txt
N.B. \\ in the variable and the variable is surrouded by "'s in the sed command.

Resources