| Newsgroups |
gmane.editors.sed.user |
| Message-ID |
<[email protected]> |
On 28/05/2015 03:42, [email protected] [sed-users] wrote:
> I received an email from Anders Granlund (in Sweden) pointing out a
> subtle error in the GNU sed manual definitions of t and T (T is a GNU
> extension). I've explored this and think Anders is right.
I agree with your reasoning. Adding the GNU sed maintainer.
Paolo
> "Branch to label only if there has been a successful substitution
> since the last input line was read or conditional branch was taken." is
> the current wording in the GNU sed manual for t.
>
> "Branch to label only if there has been a successful substitution
> since the last input line was read or conditional branch was run." seems
> to me a more correct wording.
>
> The current definition for t and T ends with "taken" (ie, branch
> taken). The suggested change ends with "run" (ie, t or T run). By
> "conditional branch", it means t or T, and "branch was taken" means t or
> T branched.
>
> The original description of sed (from 1970's) says: "The t function
> tests whether any successful substitutions have been made on the current
> input line; if so, it branches to 'label'; if not, it does nothing. The
> flag which indicates that a successful substitution has been executed is
> reset by: 1) reading a new input line, or 2) executing a t function."
> The phrase "executing a t function" seems consistent to me with "t was
> run", not "branch was taken". So that is one line of reasoning that the
> GNU sed manual seems in error.
>
> The other line of reasoning is to look at what sed does. Here is a
> test script I made up to look at cases that might arise:
>
> $ cat test1.sh
> echo "Input to sed is always the string 'old'"
> echo "----------------------------------------------------------"
> echo "Cases 1-4 are easy, as flag does not get reset"
> echo "----------------------------------------------------------"
> echo "Case 1. s works, sets flag, so t branches past d"
> echo "Case 1. Point is that t branches if flag is set"
> echo old | sed "s/old/new/; t; d"
> echo "----------------------------------------------------------"
> echo "Case 2. s fails, flag not set, so T branches past d"
> echo "Case 2. Point is that T branches if flag not set"
> echo old | sed "s/---/new/; T; d"
> echo "----------------------------------------------------------"
> echo "Case 3. s fails, flag not set, so t does not branch"
> echo "Case 3. Point is that t does not branch if flag not set"
> echo old | sed "s/---/new/; t; d"
> echo "----------------------------------------------------------"
> echo "Case 4. s works, sets flag, so T does not branch"
> echo "Case 4. Point is that T does not branch if flag set"
> echo old | sed "s/old/new/; T; d"
> echo "----------------------------------------------------------"
> echo "Cases 5-8 see if flag gets reset after s works"
> echo "----------------------------------------------------------"
> echo "Case 6. s works, tx branches, flag reset, t fails"
> echo "Case 6. Point is that t flag is reset if t branches"
> echo old | sed "s/old/new/; tx; d; :x t; l"
> echo "----------------------------------------------------------"
> echo "Case 6. s works, tx branches, flag reset, T branches"
> echo "Case 6. Point is that T flag is reset if t branches"
> echo old | sed "s/old/new/; tx; d; :x T; l"
> echo "----------------------------------------------------------"
> echo "Case 7. s works, Tx fails, flag reset, T branches"
> echo "Case 7. Point is that T flag is reset if T fails"
> echo old | sed "s/old/new/; Tx; l; :x T; d"
> echo "----------------------------------------------------------"
> echo "Case 8. s works, Tx fails, flag reset, t fails"
> echo "Case 8. Point is that t flag is reset if T fails"
> echo old | sed "s/old/new/; Tx; l; :x t; d"
> echo "----------------------------------------------------------"
> echo "Cases 9-10 see if flag gets reset by s just running"
> echo "----------------------------------------------------------"
> echo "Case 9. s1 works, s2 fails, but t still branches due to s1"
> echo "Case 9. Point is that flag is not reset by s just running"
> echo old | sed "s/old/new/; s/---/new/; t; d"
> echo "----------------------------------------------------------"
> echo "Case 10. s1 works, s2 fails, but T still fails due to s1"
> echo "Case 10. Point is that flag is not reset by s just running"
> echo old | sed "s/old/new/; s/---/new/; T; d"
> echo "----------------------------------------------------------"
>
> Here is what results:
>
> $ ./test1.sh
> Input to sed is always the string 'old'
> ----------------------------------------------------------
> Cases 1-4 are easy, as flag does not get reset
> ----------------------------------------------------------
> Case 1. s works, sets flag, so t branches past d
> Case 1. Point is that t branches if flag is set
> new
> ----------------------------------------------------------
> Case 2. s fails, flag not set, so T branches past d
> Case 2. Point is that T branches if flag not set
> old
> ----------------------------------------------------------
> Case 3. s fails, flag not set, so t does not branch
> Case 3. Point is that t does not branch if flag not set
> ----------------------------------------------------------
> Case 4. s works, sets flag, so T does not branch
> Case 4. Point is that T does not branch if flag set
> ----------------------------------------------------------
> Cases 5-8 see if flag gets reset after s works
> ----------------------------------------------------------
> Case 6. s works, tx branches, flag reset, t fails
> Case 6. Point is that t flag is reset if t branches
> new$
> new
> ----------------------------------------------------------
> Case 6. s works, tx branches, flag reset, T branches
> Case 6. Point is that T flag is reset if t branches
> new
> ----------------------------------------------------------
> Case 7. s works, Tx fails, flag reset, T branches
> Case 7. Point is that T flag is reset if T fails
> new$
> new
> ----------------------------------------------------------
> Case 8. s works, Tx fails, flag reset, t fails
> Case 8. Point is that t flag is reset if T fails
> new$
> ----------------------------------------------------------
> Cases 9-10 see if flag gets reset by s just running
> ----------------------------------------------------------
> Case 9. s1 works, s2 fails, but t still branches due to s1
> Case 9. Point is that flag is not reset by s just running
> new
> ----------------------------------------------------------
> Case 10. s1 works, s2 fails, but T still fails due to s1
> Case 10. Point is that flag is not reset by s just running
> ----------------------------------------------------------
>
> The key cases are #7 and #8. In both cases, s substituted, so T did
> not branch. According to the current GNU sed manual, branching is
> required to reset the flag. But the flag was reset, so T branches next
> time it appears, and t does not branch next time it appears. Merely
> running t or T, even if no branch, is enough to reset the flag.
>
> I don't think this is a big deal. It seems rather obscure, something
> that had never crossed my mind until Anders found it. I would always put
> t or T immediately after the s command, so cases 7 and 8 would rarely or
> never occur in practice. It seems like asking for trouble to have
> multiple t/T commands scattered about. But who knows? Maybe this might
> come up in some games that get programmed in complex sed scripts.
>
> Whether this is good style or not, the point is the current wording
> seems incorrect. If the manual is incorrect, I hope it can get fixed. If
> the current wording is OK, I'd be interested to hear what Anders and I
> missed.
>
> Thanks,
> Daniel
>
>
> ------------------------------------
> Posted by: [email protected]
> ------------------------------------
>