From 553aca42f74a8712cef8a3387ff2131102551ff0 Mon Sep 17 00:00:00 2001 From: Jussi Maki Date: Thu, 5 Dec 2024 15:22:32 +0100 Subject: [PATCH] script: Implement simple "sed" command The simple 'replace' command falls short in situations where the input text isn't fully known, but still needs to be sanitized in some way. Instead of having to use e.g. the system 'sed' command, implement a very simple built-in version. Signed-off-by: Jussi Maki --- script/cmds.go | 40 ++++++++++++++++++++++++++++++ script/scripttest/testdata/sed.txt | 20 +++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 script/scripttest/testdata/sed.txt diff --git a/script/cmds.go b/script/cmds.go index a72abb2..8c74912 100644 --- a/script/cmds.go +++ b/script/cmds.go @@ -44,6 +44,7 @@ func DefaultCmds() map[string]Cmd { "mv": Mv(), "rm": Rm(), "replace": Replace(), + "sed": Sed(), "sleep": Sleep(), "stderr": Stderr(), "stdout": Stdout(), @@ -882,6 +883,45 @@ func Replace() Cmd { }) } +// Sed implements a simple regexp replacement of text in a file. +func Sed() Cmd { + return Command( + CmdUsage{ + Summary: "substitute strings in a file with a regexp", + Args: "regexp replacement file", + Detail: []string{ + "A simple sed-like command for replacing text matching regular expressions", + "in a file.", + "", + "Implemented using regexp.ReplaceAll, see its docs for what is supported:", + "https://pkg.go.dev/regexp#Regexp.ReplaceAll", + }, + RegexpArgs: firstNonFlag, + }, + func(s *State, args ...string) (WaitFunc, error) { + if len(args) != 3 { + return nil, ErrUsage + } + + re, err := regexp.Compile(args[0]) + if err != nil { + return nil, err + } + replacement := args[1] + file := s.Path(args[2]) + + data, err := os.ReadFile(file) + if err != nil { + return nil, err + } + lines := strings.Split(string(data), "\n") + for i, line := range lines { + lines[i] = re.ReplaceAllString(line, replacement) + } + return nil, os.WriteFile(file, []byte(strings.Join(lines, "\n")), 0666) + }) +} + // Rm removes a file or directory. // // If a directory, Rm also recursively removes that directory's diff --git a/script/scripttest/testdata/sed.txt b/script/scripttest/testdata/sed.txt new file mode 100644 index 0000000..4c33b5e --- /dev/null +++ b/script/scripttest/testdata/sed.txt @@ -0,0 +1,20 @@ +# Tests for the sed command + +sed '' '' input.txt +sed notfound unexpected input.txt +sed \d+ N input.txt +sed [uz] '' input.txt +sed a(x*)b 'a${1}c' input.txt +sed ^(s+)$ '${1}${1}' input.txt +cmp input.txt expected.txt + +-- input.txt -- +foo123bar +quuxbaz123 +axxxxxxb +sss +-- expected.txt -- +fooNbar +qxbaN +axxxxxxc +ssssss