Skip to main content

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 a for loop, turning any output into the $file variable
  • find . -iname "*.php" searches the current directory recursively for file names that end with .php
  • 2>/dev/null supresses find errors by redirecting them to null
  • do sed -i '\[\([^]]*\)\]/\["\1"\]/g' $file runs the sed command against any php files found
  • done informs the bash to end the for 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.

graphic that says Adam and shows an exclamation point

Adam Anderson

Systems Administrator by day; ronin illustrator by night. I promote learning the tools in your computer system to complete your work in a more effective way, meanwhile agonizing for hours over an A3 sheet of bristol paper with a 0.03mm pen.