sed edits a stream line by line. Its workhorse is s/pattern/replacement/flags, where -E enables extended regular expressions, \1 recalls the first group, g replaces every match, and any character may stand in for /. An address such as 5, $, /regex/ or /start/,/end/ limits a command to some lines, and -n turns off automatic printing so that p prints on demand. On a server, sed's main job is scripted configuration; -i.bak edits in place and keeps the original.
cp /etc/php/8.5/fpm/php.ini .
sed -i.bak -E \
-e 's/^memory_limit = .*/memory_limit = 256M/' \
-e 's/^upload_max_filesize = .*/upload_max_filesize = 32M/' \
-e 's|^;date.timezone =.*|date.timezone = Asia/Kuala_Lumpur|' php.ini
grep -nE '^(memory_limit|upload_max_filesize|date.timezone) ' php.ini
sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+ /\1.0 /' access.log | cut -d' ' -f1 | sort | uniq -c430:memory_limit = 256M
851:upload_max_filesize = 32M
964:date.timezone = Asia/Kuala_Lumpur
5 127.0.0.0
4 172.23.160.0
3 192.0.2.0
500 203.0.113.0
5 ::1The third expression uncomments ;date.timezone and sets it in one step, its | delimiter sparing you from escaping the slash. The mask shows a classic trap: it handles IPv4 only, so the ::1 lines pass through untouched. Run a script without -i first, and test with sudo php-fpm8.5 -t before a reload. A bare -i is GNU-only (BSD sed on macOS wants -i ''); -i.bak works on both.