replace recursively shabang with sed - bash

I'm trying to replace recursively all shabang from a folder (for run program in android..), with sed .
The command works good when i tried with "normal word" but become a headache when i'm trying with shabang..Everything i tried, I got error :
bad option in substitution expression
unmatched '/'
event not found
I'm new to this and it's probably begginer mistake, so here is the code (tsst is my folder):
grep -rl "env python" tsst |xargs sed -i "s/\#!/usr/bin/env python/\#!/system/python2.7.9//g"
I also tried with variables:(first part of code is good .. i just copy where there's a problem.)
sed -i "s/$old/$new/g"
sed -i 's/"$old"/"$new"/g'
sed -i "s/'\#!\/usr\/bin\/env python'/'\#!\/system\/python2.7.9\/'/g"
What did i do wrong ?

Try this regex. You can't mix / as the regex delimiter and actual characters you want to match. You can use any character as the regex delimiter, such as |, as long as you use it instead of the / in all 3 spots.
$ echo '#!/usr/bin/env python' | sed 's|#!/usr/bin/env python|#!/system/python2.7.9|g'
#!/system/python2.7.9

Related

How to delete a line from a file containing '(' and a variable using bash

I have a file named xyz.txt and a varibale delVar=123.
I need to delete a line from xyz.txt having string:
Some (text($delVar
I tried multiple combinations of sed and awk :
sed -i "/Some\\\(text\\\($delVar/d" xyz.txt
Doesn't work.
sed -i '/Some\\(text\\('"$delVar"'/d' xyz.txt
Doesn't work either.
When I try to bypass '(' using single \, the error "unmatched ( or (" comes up.
I am using cygwin to run this.
My .sh file:
accountId=$1
Number=$2
temp="Example"
grep $temp History.txt > $Number-History.txt
sed -i '/VALUES (CAST('"$accountId"'/d' $Number-History.txt
sed -i '/, CAST('"$accountId"' /!d' $Number-History.txt
sed -i 's/History.txt:/ /' $Number-History.txt
HistCount=$(wc -l < "$Number-History.txt")
echo $HistCount
My command:
./MyFile.sh 123 ABC000987
Here, when I save 123 in accountId and try to set it in my pattern, it matches patters with the number 1234, 1123 etc also
As stated by Sundeep in a comment, you do not need to escape the ( because sed by default uses basic regex expressions (where ( and + and others do not need to be escaped to match a literal ( or +, etc.).
But you do need to escape the $, because $ matches the end of the pattern space.
sed -i "/Some(text(\$delVar/d" xyz.txt
should work.
If you want to use extended regex expressions, use the -r flag.
sed -ir "/Some\(text\(\$delVar/d" xyz.txt
Now you need to escape the (s as well as the $s.

sed doesn't catch all sets of doubles

I've writted a sed script to replace all ^^ with NULL. It seems though that sed is only catching a pair, but not including the second in that pair as it continues to search.
echo "^^^^" | sed 's/\^\^/\^NULL\^/g'
produces
^NULL^^NULL^
when it should produce
^NULL^NULL^NULL^
Try with a loop to apply your command again to modified pattern space:
echo "^^^^" | sed ':a;s/\^\^/\^NULL\^/;t a;'
To edit a file in place on OSX, try the -i flag and multiline command:
sed -i '' ':a
s/\^\^/\^NULL\^/
t a' file
With GNU sed:
sed -i ':a;s/\^\^/\^NULL\^/;t a;' file
or simply redirect the command to a temporary file before renaming it:
sed ':a;s/\^\^/\^NULL\^/;t a;' file > tmp && mv tmp file
I really like SLePort solution, but since it is not working for you, you can try with (tested on Linux, not Mac):
echo "^^^^" | sed 's/\^\^/\^NULL\^/g; s//\^NULL\^/g'
It is doing the same as the former solution, but explicitly, not looping with tags.
You can omit the pattern in the second command and sed will use the previous pattern.

Replacing a pattern using sed

I am trying to replace all the patterns
s#_coded_block[#] with s#_coded_block_# in myfile. I looked online on how to replace patterns with groupings and my command is:
sed -i -E 's/s\([0-9]*\)_coded_block\[\([0-9]*\)\]/s\1_coded_block_\2/g' myfile
However, I am getting
invalid reference \2 on `s'
command's RHS when I execute this command.
With the -E option, you don't need backslashes before the capturing parentheses:
sed -i -E 's/s([0-9]*)_coded_block\[([0-9]*)\]/s\1_coded_block_\2/g' myfile
You might want one-or-more digits, in which case you use + instead of *. If you decide to drop the -E, your original code should work, though if you want at least one digit, you need to write \{1,\}:
sed -i 's/s\([0-9]\{1,\}\)_coded_block\[\([0-9]\{1,\}\)\]/s\1_coded_block_\2/g' myfile
The -i notation shown only works reliably with GNU sed. BSD (macOS or Mac OS X) sed would treat the -E in the first command line as the suffix (in the second, you'd get a complaint about m not being a valid sed command because the script would be treated as the suffix and the m of myfile would be an erroneous sed command. You'd use -i '' to back up (overwrite) a file with no suffix. If you want portable code, use -i.bak which creates a backup file with both variants — the .bak must be attached to the -i for GNU sed.

Replacing "#", "$", "%", "&", and "_" with "\#", "\$", "\%", "\&", and "\_"

I have a plain text document, which I want to compile inside LaTeX. However, sometimes it has the characters, "#", "$", "%", "&", and "_". To compile properly in LaTeX, I must first replace these characters with "#", "\$", "\%", "\&", and "_". I have used this line in sed:
sed -i 's/\#/\\\#/g' ./file.txt
sed -i 's/\$/\\\$/g' ./file.txt
sed -i 's/\%/\\\%/g' ./file.txt
sed -i 's/\&/\\\&/g' ./file.txt
sed -i 's/\_/\\\_/g' ./file.txt
Is this correct?
Unfortunately, the file is too large to open in any GUI software, so checking if my sed line is correct with a text editor is difficult. I tried searching with grep, but the search does not work as expected (e.g. below, I searched for any lines containing "$"):
grep "\$" file.txt
What is the best way to put "\" in front of these characters?
How can I use grep to successfully check the lines with the replacements?
You can do the replacement with a single call to sed:
sed -i -E 's/([#$%&_\])/\\&/g' file.txt
The & in the replacement text fills in for whichever single character is enclosed in parentheses. Note that since \ is the LaTeX escape character, you'll have to escape it as well in the original file.
sed -i 's/\#/\\\#/g' ./file.txt
sed -i 's/\$/\\\$/g' ./file.txt
sed -i 's/\%/\\\%/g' ./file.txt
sed -i 's/\&/\\\&/g' ./file.txt
sed -i 's/\_/\\\_/g' ./file.txt
You don't need the \ on the first (search) string on most of them, just $ (it's a special character, meaning the end of a line; the rest aren't special). And in the replacement, you only need two \\, not three. Also, you could do it all in one with several -e statements:
sed -i.bak -e 's/#/\\#/g' \
-e 's/\$/\\$/g' \
-e 's/%/\\%/g' \
-e 's/&/\\&/g' \
-e 's/_/\\_/g' file.txt
You don't need to double-escape anything (except the \\) because these are single-quoted. In your grep, bash is interpreting the escape on the $ because it's a special character (specifically, a sigil for variables), so grep is getting and searching for just the $, which is a special character meaning the end of a line. You need to either single-quote it to prevent bash from interpreting the \ ('\$', or add another pair of \\: "\\\$". Presumably, that's where you're getting the\` from, but you don't need it in the sed as it's written.
I think your problem is that bash itself is handling those escapes.
What you have looks right to me. But warning: it will also doubly escape e.g. a \# that is already escaped. If that's not what you want, you might want to modify your patterns to check that there isn't a preceding \ already.
$ is used for bash command substitution syntax. I guess grep "\\$" file.txt should do what you expect.
I do not respond for sed, the other answers are good enougth ;-)
You can use less as viewer to check your huge file (or more, but less is more comfortable than more).
For searching, you can use fgrep: it ignores regular expression => fgrep '\$' will really search for text \$. fgrep is the same as invoking grep -F.
EDIT:
fgrep '\$' and fgrep "\$" are different. In the second case, bash interprets the string and will replace it by a single character: $ (i.e. fgrep will search for $ only).

using sed to find and replace in bash for loop

I have a large number of words in a text file to replace.
This script is working up until the sed command where I get:
sed: 1: "*.js": invalid command code *
PS... Bash isn't one of my strong points - this doesn't need to be pretty or efficient
cd '/Users/xxxxxx/Sites/xxxxxx'
echo `pwd`;
for line in `cat myFile.txt`
do
export IFS=":"
i=0
list=()
for word in $line; do
list[$i]=$word
i=$[i+1]
done
echo ${list[0]}
echo ${list[1]}
sed -i "s/{$list[0]}/{$list[1]}/g" *.js
done
You're running BSD sed (under OS X), therefore the -i flag requires an argument specifying what you want the suffix to be.
Also, no files match the glob *.js.
This looks like a simple typo:
sed -i "s/{$list[0]}/{$list[1]}/g" *.js
Should be:
sed -i "s/${list[0]}/${list[1]}/g" *.js
(just like the echo lines above)
So myFile.txt contains a list of from:to substitutions, and you are looping over each of those. Why don't you create a sed script from this file instead?
cd '/Users/xxxxxx/Sites/xxxxxx'
sed -e 's/^/s:/' -e 's/$/:/' myFile.txt |
# Output from first sed script is a sed script!
# It contains substitutions like this:
# s:from:to:
# s:other:substitute:
sed -f - -i~ *.js
Your sed might not like the -f - which means sed should read its script from standard input. If that is the case, perhaps you can create a temporary script like this instead;
sed -e 's/^/s:/' -e 's/$/:/' myFile.txt >script.sed
sed -f script.sed -i~ *.js
Another approach, if you don't feel very confident with sed and think you are going to forget in a week what the meaning of that voodoo symbols is, could be using IFS in a more efficient way:
IFS=":"
cat myFile.txt | while read PATTERN REPLACEMENT # You feed the while loop with stdout lines and read fields separated by ":"
do
sed -i "s/${PATTERN}/${REPLACEMENT}/g"
done
The only pitfall I can see (it may be more) is that if whether PATTERN or REPLACEMENT contain a slash (/) they are going to destroy your sed expression.
You can change the sed separator with a non-printable character and you should be safe.
Anyway, if you know whats on your myFile.txt you can just use any.

Resources