From a75c339a691be98c62ebbee26198e5720072878f Mon Sep 17 00:00:00 2001 From: Rong Zhang Date: Wed, 22 Jul 2026 01:50:49 +0800 Subject: scripts/config: Use in-place editing (-i) in sed portably The use of in-place editing was removed by commit 83e8b90e1d2c ("scripts/config: use sed's POSIX interface"). Before that, the script used bare `-i' to skip creating a backup file. In fact, major sed implementations have supported `-i' for over a decade. It's really doubtful if anyone would still build Linux on a Unix system without it. The issue is more about how we use it: FreeBSD and macOS disallow bare `-i'. To skip creating a backup, an empty string ("zero-length extension") must be passed as a separate argument following `-i'. GNU and other BSDs accept bare `-i' to skip creating a backup, but disallow passing a zero-length extension. That being said, when thinking about it optimistically, using `-i' is portable as long as a backup is created. Use in-place editing (-i) in a portable manner by creating a backup file with a .swp extension (the same name as the current temporary file). The backup file will be deleted on exit. A rough benchmark with ~1000 editions showed a 14.4% speedup (5.27s => 4.51s, GNU sed). The FreeBSD sed showed a similar speedup. Reviewed-by: Nicolas Schier Signed-off-by: Rong Zhang Link: https://patch.msgid.link/20260722-config-sed-v2-2-9f2c4b164666@rong.moe Signed-off-by: Nicolas Schier --- scripts/config | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'scripts') diff --git a/scripts/config b/scripts/config index 6582b200967c..32428ea909c2 100755 --- a/scripts/config +++ b/scripts/config @@ -71,35 +71,34 @@ txt_append() { local anchor="$1" local insert="$2" local infile="$3" - local tmpfile="$infile.swp" # sed append cmd: 'a\' + newline + text + newline cmd="$(printf "a\\%b$insert" "\n")" - sed -E -e "/$anchor/$cmd" "$infile" >"$tmpfile" - # replace original file with the edited one - mv "$tmpfile" "$infile" + # We don't really need a backup file, but in-place editing with backup + # skipped is not portable due to different implementations parsing + # arguments in incompatible manners. + # Create a backup file anyway to ensure portability. The file will be + # deleted on exit. + sed -E -i.swp -e "/$anchor/$cmd" "$infile" + SED_EDITED=1 } txt_subst() { local before="$1" local after="$2" local infile="$3" - local tmpfile="$infile.swp" - sed -E -e "s$SED_DELIM$before$SED_DELIM$after$SED_DELIM" "$infile" >"$tmpfile" - # replace original file with the edited one - mv "$tmpfile" "$infile" + sed -E -i.swp -e "s$SED_DELIM$before$SED_DELIM$after$SED_DELIM" "$infile" + SED_EDITED=1 } txt_delete() { local text="$1" local infile="$2" - local tmpfile="$infile.swp" - sed -E -e "/$text/d" "$infile" >"$tmpfile" - # replace original file with the edited one - mv "$tmpfile" "$infile" + sed -E -i.swp -e "/$text/d" "$infile" + SED_EDITED=1 } set_var() { @@ -122,6 +121,14 @@ undef_var() { txt_delete "^($name=|# $name is not set)" "$FN" } +SED_EDITED=0 +on_exit() { + if [ "$SED_EDITED" -ge 1 ]; then + rm -f "$FN.swp" + fi +} +trap on_exit EXIT + FN=.config CMDS=() while [[ $# -gt 0 ]]; do -- cgit v1.2.3