Sed over BASH escaping - bash

I am looking to go through our site and remove the encoded hard paths and replace them with $_SERVER['DOCUMENT_ROOT'] over a shell connection, but I am not sure how to escape it correctly.
Need to replace
"/home/imprint/public_html/template
With
$_SERVER['DOCUMENT_ROOT']."/template
Here is what I found to do it, but I also need to include .htm files and I am not sure what I need to escape.
find . -name '*.php' -exec sed -i 's/"/home/imprint/public_html/template/$_SERVER['DOCUMENT_ROOT']."/template/g' {} \;
Also, what does the -i option do in sed?

You can combine find clauses with -o ("or")
If you use different delimiters for the sed s command, you don't need to escape anything.
search='"/home/imprint/public_html/template'
replace='$_SERVER['DOCUMENT_ROOT']."/template'
find . -name '*.php' -o -name '*.htm' \
-exec sed -i "s#${search}#${replace}#g" {} +
To gain efficiency by reducing the number of times sed is invoked, use -exec ... + instead of -exec ... \;

If you're replacing a fixed string with another one, you can use sed with single quotes rather than doubles, as it will prevent any interpretation of the $ sign or other unpredicted funkiness.
Also since you're replacing pathes, fyi you can use other chars than / as sed's delimiter (i.e. sed "s=abc=def=g"), which is probably clearer.
From the man page :
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)

Maybe you can try the next
shopt -s globstar
perl -i.bak -pe 's:/home/imprint/public_html/(template):\$_SERVER['DOCUMENT_ROOT']/$1:' ./**/*.php
will create backup file .bak
the ./**/*.php will search for all php files recusively if the globstar option is set

Related

Error using sed with -i flag inside a bash for loop [duplicate]

Being forced to use CVS for a current client and the address changed for the remote repo. The only way I can find to change the remote address in my local code is a recursive search and replace.
However, with the sed command I'd expect to work:
find ./ -type f -exec sed -i "s/192.168.20.1/new.domain.com/" {} \;
I get an error for every file:
sed: 1: ".//file/path ...": invalid command code .
I've tried to escape the periods in the sed match/replacement but that doesn't solve anything.
If you are on a OS X, this probably has nothing to do with the sed command. On the OSX version of sed, the -i option expects an extension argument so your command is actually parsed as the extension argument and the file path is interpreted as the command code.
Try adding the -e argument explicitly and giving '' as argument to -i:
find ./ -type f -exec sed -i '' -e "s/192.168.20.1/new.domain.com/" {} \;
See this.
On OS X nothing helps poor builtin sed to become adequate. The solution is:
brew install gnu-sed
And then use gsed instead of sed, which will just work as expected.
You simply forgot to supply an argument to -i. Just change -i to -i ''.
Of course that means you don't want your files to be backed up; otherwise supply your extension of choice, like -i .bak.
Simply add an extension to the -i flag. This basically creates a backup file with the original file.
sed -i.bakup 's/linenumber/number/' ~/.vimrc
sed will execute without the error
It is not the case for the OP but it was for me and could help someone else.
If you are using ' to enclose regex, double check the ' characters. I was copying and pasting the script from word processing and it was pasting ' as ’ in bash.
Probably your new domain contain / ? If so, try using separator other than / in sed, e.g. #, , etc.
find ./ -type f -exec sed -i 's#192.168.20.1#new.domain.com#' {} \;
It would also be good to enclose s/// in single quote rather than double quote to avoid variable substitution or any other unexpected behaviour

How to correctly combine find, sed & tr to replace a newline in all my files

All of my PHP files currently start
<?php
declare(strict_types=1);
It's a minor thing, but I'd like to change them all to
<?php declare(strict_types=1);
I think I need to use tr as sed works on a single line at a time. But I can't come up with the right command to recursively do this through a directory of .php files.
Thanks!
You can try that out with GNU sed:
find . -name *.php -exec sed -i '1{N;s/<?php\s*\n\s*declare/<?php declare/}' {} \;
The find bit retrieves all .php files in the current directory, the sed bit edits them in-place to change a matched two-line definition into a one-line definition.
It assumes the php opening tag is in the first line, and looks for a second line starting with declare (and optional spaces).
If you don't use GNU sed, this command should be posix compliant :
find . -name *.php -exec sed -i.bak '1{N;s/<?php[[:space:]]*\Enter[[:space:]]*declare/<?php declare/}' {} \;
However it also creates backups of the .php files, which can be removed once sure of the success of the command with an additional find :
find . -name *.php.bak -delete

using find with variables in bash

I am new to bash scripting and need help:
I need to remove specific files from a directory . My goal is to find in each subdirectory a file called "filename.A" and remove all files that starts with "filename" with extension B,
that is: "filename01.B" , "filename02.B" etc..
I tried:
B_folders="$(find /someparentdirectory -type d -name "*.B" | sed 's# (.*\)/.*#\1#'|uniq)"
A_folders="$(find "$B_folders" -type f -name "*.A")"
for FILE in "$A_folders" ; do
A="${file%.A}"
find "$FILE" -name "$A*.B" -exec rm -f {}\;
done
Started to get problems when the directories name contained spaces.
Any suggestions for the right way to do it?
EDIT:
My goal is to find in each subdirectory (may have spaces in its name), files in the form: "filename.A"
if such files exists:
check if "filename*.B" exists And remove it,
That is: remove: "filename01.B" , "filename02.B" etc..
In bash 4, it's simply
shopt -s globstar nullglob
for f in some_parent_directory/**/filename.A; do
rm -f "${f%.A}"*.B
done
If the space is the only issue you can modify the find inside the for as follows:
find "$FILE" -name "$A*.B" -print0 | xargs -0 rm
man find shows:
-print0
True; print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows
file names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output. This option corre-
sponds to the -0 option of xargs.
and xarg's manual
-0 Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every character is taken literal-
ly). Disables the end of file string, which is treated like any other argument. Useful when input items might contain white space, quote marks, or
backslashes. The GNU find -print0 option produces input suitable for this mode.

Substitute string in BASH with Sed (when it has special characters)

It's a fairly simple question and I'm sure the gurus here can figure it out right away, however I don't seem to be able to make it work (probably some quotes issue.
I want to place all instances of:
`which cat`
With the following:
/bin/cat
I am running the following command:
for file in $(find . -iname 'PATCH*'); do sed 's/\`which cat\`/\'\/bin\/cat/g' $file; done
I believe I have escaped all characters that don't need to be treated as special ones, however it doesn't seem to do the trick.
Please help :)
It is generally not a good idea to iterate over the output of find since file names can contain the $IFS which would break the loop. Use the -exec option of find instead:
find -iname 'PATCH*' -exec sed -i 's#`which cat`#/bin/cat#g' {} \;
Use a different sed delimiter.
sed 's~`which cat`~/bin/cat~g' file
Example:
$ echo '`which cat`' | sed 's~`which cat`~/bin/cat~g'
/bin/cat

How to overwrite the contents in the sed, without having backup file

I have a command like this:
sed -i -e '/console.log/ s/^\/*/\/\//' *.js
which does comments out all console.log statements. But there are two things
It keeps the backup file like test.js-e , I doesn't want to do that.
Say I want to the same process recursive to the folder, how to do it?
You don't have to use -e option in this particular case as it is unnecessary. This will solve your 1st problem (as -e seems to be going as suffix for -i option).
For the 2nd part, u can try something like this:
for i in $(find . -type f -name "*.js"); do sed -i '/console.log/ s/^\/*/\/\//' $i; done;
Use find to recursively find all .js files and do the replacement.
When checking sed's help, -i takes a suffix and uses it as a backup,
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if SUFFIX supplied)
and the output backup seems to be samefile + -e which is the second argument you're sending, try removing the space and see if that would work
sed -ie '/console.log/ s/^\/*/\/\//' *.js
As for the recursion, you could use find with -exec or xargs, please modify the find command and test it before running exec
find -name 'console.log' -type f -exec sed -ie '/console.log/ s/^\/*/\/\//' *.js \;
From your original post I presume you just want to make a C-style comment leading like:
/*
to a double back-slash style like:
//
right?
Then you can do it with this command
find . -name "*.js" -type f -exec sed -i '/console.log/ s#^/\*#//#g' '{}' \;
To be awared that:
in sed the split character normally be / but if you found that annoying to Escape when your replacing or matching string contains a / . You can change the split character to # or | as you like, I found it very useful trick.
if you do want to do is what I presumed, be sure that you should Escape the character *, because a combination of regex /* just means to match a pattern that / occurs one time or many times or none at all, that will match everything, it's very dangerous!

Resources