Recently I was tasked with updating some PHP on a client’s website for future compatibility, which includes replacing instances of retrieving json variables that were written without quotations inside the brackets. There are times when editing a file you want to replace text with variable data within that text, such as with brackets, but only if there is a closing bracket. The length of text may vary.
Throughout their website their were code snippets like the one below:
php
name=json[name];
description=json[description];
date=json[date];
The ideal end result looks liked this:
php
name=json["name"];
description=json["description"];
date=json["date"];
While I could have scoured through their site and individually updated every string of text, instead I made a backup of their existing site’s php file where the code snippets were stored and ran the following and copying the backup file to a second location:
bash
sed -i 's/\[\([^]]*\)\]/\["\1"\]/g' example.php
After verifying the file I uploaded the file to their web host and the server’s cache was cleared and verified in the logs that the future compatibility errors had cleared.
Let’s Break it Down
What did I do, exactly?
s
tells sed to run on each line in the file\[
is looking for the square bracket, the back slash is an escape to include the bracket as a text character\([^]]*\)
is the text after the the opening square bracket, up to but not including the closing square bracket\]
is the closing square bracket
The above signifies to find the text surrounded by []
brackets, including the brackets. The contents between \(
and \)
is now a captured group and can be reprinted with a \1
.
\["
prints an opening square bracket and a double quotes before the\1
\1
prints the captured group"\]
prints the closing double quotes and the closing square bracket after the\1
Finally, since this occurs multiple times throughout the php we need to run the script globally with g
Taking It a Step Further
This client’s site was simpler than most, however not every site has only a single PHP file to be concerned about. While it likely isn’t a problem to run the above command against every file, it makes sense to only run it against .php files.
bash
cd backupdir
for file in $(find . -iname "*.php" 2>/dev/null); do sed -i 's/\[\([^]]*\)\]/\["\1"\]/g' $file; done
Breaking it Down Again
for file in $();
is the start of afor
loop, turning any output into the$file
variablefind . -iname "*.php"
searches the current directory recursively for file names that end with.php
2>/dev/null
supresses find errors by redirecting them tonull
do sed -i '\[\([^]]*\)\]/\["\1"\]/g' $file
runs the sed command against any php files founddone
informs the bash to end thefor
loop
Closing Thoughts
The highly versatile sed command has saved me several hours of manually combing through PHP code with greater accuracy than any human could dream to achieve. Having sed in your toolbelt is great not just for systems administrators and Linux enthusiasts, but for web developers as well.
I hope you found this information useful and were able to add it to your toolbox of useful commands.