This does indeed seems like a bug to me. The -i flag should produce
similar output for in place as it does without it.
$ printf '1\n2\n3\n' | tee /tmp/test > /tmp/test1
$ sed 's/2/4/;2q' /tmp/test
1
4
$ sed -i 's/2/4/;2q' /tmp/test
$ cat /tmp/test
1
2
3
$ cat /tmp/sedYwXsFr7jxg
1
4
So the output is there, but it's not stored after the quit command.
The diff below fixes this. Note that I took special care to make a
distinction between in place and normal for the 'q' command.
When running normally the files are concatenated, so we should quit
immediately. When running in in place mode I reckon the script
should be treated as if it were to run for every file individually,
since the line numbers are also reset in between files.
The following diff fixes that.
Note that this differs from what gnu sed does, since they decide
to not apply the script on the second file, but do apply it on the
first file:
$ gsed -i 's/2/4/;2q' /tmp/test /tmp/test1
$ cat /tmp/test
1
4
$ cat /tmp/test1
1
2
3
OK?
martijn@
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.bin/sed/extern.h,v
retrieving revision 1.13
diff -u -p -r1.13 extern.h
--- extern.h 1 Aug 2017 18:05:53 -0000 1.13
+++ extern.h 14 Aug 2018 08:40:57 -0000
@@ -42,7 +42,9 @@ extern u_long linenum;
extern size_t appendnum;
extern int Eflag, aflag, eflag, nflag;
extern int pledge_wpath, pledge_rpath;
+extern int nextfile;
extern const char *fname, *outfname;
+extern char *inplace;
extern FILE *infile, *outfile;
void cfclose(struct s_command *, struct s_command *);
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/sed/main.c,v
retrieving revision 1.37
diff -u -p -r1.37 main.c
--- main.c 11 Jul 2018 06:57:18 -0000 1.37
+++ main.c 14 Aug 2018 08:40:57 -0000
@@ -98,6 +98,7 @@ static char oldfname[PATH_MAX]; /* Old f
static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place
editing) */
char *inplace; /* Inplace edit file extension */
u_long linenum;
+int nextfile = 0;
static void add_compunit(enum e_cut, char *);
static void add_file(char *);
@@ -338,10 +339,11 @@ mf_fgets(SPACE *sp, enum e_spflag spflag
}
for (;;) {
- if (infile != NULL && (c = getc(infile)) != EOF) {
+ if (!nextfile && infile != NULL && (c = getc(infile)) != EOF) {
(void)ungetc(c, infile);
break;
}
+ nextfile = 0;
/* If we are here then either eof or no files are open yet */
if (infile == stdin) {
sp->len = 0;
Index: process.c
===================================================================
RCS file: /cvs/src/usr.bin/sed/process.c,v
retrieving revision 1.33
diff -u -p -r1.33 process.c
--- process.c 13 Dec 2017 16:06:34 -0000 1.33
+++ process.c 14 Aug 2018 08:40:57 -0000
@@ -193,10 +193,14 @@ redirect:
}
break;
case 'q':
- if (!nflag && !pd)
- OUT();
- flush_appends();
- exit(0);
+ if (inplace == NULL) {
+ if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ exit(0);
+ }
+ nextfile = 1;
+ break;
case 'r':
if (appendx >= appendnum) {
appends = xreallocarray(appends,
On 08/13/18 23:50, Loopw wrote:
> On 2018-08-13 06:40, Tim Chase wrote:
>>> Synopsis: "sed -i" not renaming/moving temp-file
>
> sed -i works just fine for me. It's really the use of ';q' that seems to
> cause the behavior.
>
> This seems like expected behavior for sed when ;q is present.
>
>
>>> Description:
>>
>> "sed -i.bak '/2/d;q' file.txt" leaves temp file instead of renaming.
>>
>>> How-To-Repeat:
>>
>> $ mkdir sedbug
>> $ cd sedbug
>> $ jot 5 > file.txt
>> $ sed -e '/2/d;q' file.txt # expected behavior: 1 line
>> 1
>> $ sed -i.bak -e '/2/d;q' file.txt # edit it in-place
>> $ ls
>> file.txt sedpK7uniHbMN
>> $ cat file.txt # still has original contents
>> 1
>> 2
>> 3
>> 4
>> 5
>> $ cat sedpK7uniHbMN
>> 1
>>
>> Expected results:
>>
>> the resulting temp-file (which contains the correct data) should be
>> moved back atop the original source file(s).
>>
>
>
> What does "q" do? Its not commonly used. From SED(1):
> [1addr]q
> Branch to the end of the script and quit without starting a new
> cycle.
>
>
> This is probably the command line you actually want, no '...;q' needed - will
> delete any line with "2" in it in file.txt, and will save the old one to
> file.txt.bak:
>
> sed -i.bak -e '/2/d' file.txt
>
>
> By putting ";q" in the sed command string, sed is told to cut out at the end
> of a loop. In OpenBSD, this will mean your particular sed command will exit
> out after it makes a transformation in a temp file. MacOS does something
> similar. Linux cuts the temp file out mid-way, leaving a partial result.
> Its not totally surprising to me that sed is leaving the temp file, its only
> half way done, so to speak.
>
>