diff mbox series

t3920: don't ignore errors of more than one command with `|| true`

Message ID febcfb0a-c410-fb71-cff9-92acfcb269e2@kdbg.org (mailing list archive)
State Accepted
Commit 500317ae03f635b247627eeb9760d9de2e343875
Headers show
Series t3920: don't ignore errors of more than one command with `|| true` | expand

Commit Message

Johannes Sixt Nov. 21, 2022, 5:58 p.m. UTC
It is customary to write `A || true` to ignore a potential error exit of
command A. But when we have a sequence `A && B && C || true && D`, then
a failure of any of A, B, or C skips to D right away. This is not
intended here. Turn the command whose failure is to be ignored into a
compound command to ensure it is the only one that is allowed to fail.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---
 t/t3920-crlf-messages.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

René Scharfe Nov. 21, 2022, 10:56 p.m. UTC | #1
Am 21.11.22 um 18:58 schrieb Johannes Sixt:
> It is customary to write `A || true` to ignore a potential error exit of
> command A. But when we have a sequence `A && B && C || true && D`, then
> a failure of any of A, B, or C skips to D right away. This is not
> intended here. Turn the command whose failure is to be ignored into a
> compound command to ensure it is the only one that is allowed to fail.

Good catch!

> Signed-off-by: Johannes Sixt <j6t@kdbg.org>
> ---
>  t/t3920-crlf-messages.sh | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
> index 4c661d4d54..a58522c163 100755
> --- a/t/t3920-crlf-messages.sh
> +++ b/t/t3920-crlf-messages.sh
> @@ -12,7 +12,7 @@ create_crlf_ref () {
>  	cat >.crlf-orig-$branch.txt &&
>  	cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&

Useless use of cat.

>  	grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&

My knee-jerk reaction to long lines like this is to pull out awk:

	awk '/Subject/ {printf "%s", sep $0; sep = " "}' .crlf-orig-$branch.txt >.crlf-subject-$branch.txt &&

This is not a faithful conversion because the original trims all
spaces from the end of the subject for some reason.  That would be:

	awk '/Subject/ {s = s $0 " "} END {sub(/ *$/, "", s); printf "%s", s}' .crlf-orig-$branch.txt >.crlf-subject-$branch.txt &&

> -	grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
> +	{ grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true; } &&

OK, back on topic: Adding CRs explicitly instead of relying on grep to
pass them through (which it doesn't on MinGW) also ignores the return
value of grep as a side effect of the pipe:

	grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt &&

>  	LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
>  	test_tick &&
>  	hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) &&
Junio C Hamano Nov. 22, 2022, 12:53 a.m. UTC | #2
René Scharfe <l.s.r@web.de> writes:

>> @@ -12,7 +12,7 @@ create_crlf_ref () {
>>  	cat >.crlf-orig-$branch.txt &&
>>  	cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
>
> Useless use of cat.

Very good eyes.

> OK, back on topic: Adding CRs explicitly instead of relying on grep to
> pass them through (which it doesn't on MinGW) also ignores the return
> value of grep as a side effect of the pipe:
>
> 	grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt &&

Very nice.
Philippe Blain Nov. 22, 2022, 6:28 p.m. UTC | #3
Hi Johannes,

Le 2022-11-21 à 12:58, Johannes Sixt a écrit :
> It is customary to write `A || true` to ignore a potential error exit of
> command A. But when we have a sequence `A && B && C || true && D`, then
> a failure of any of A, B, or C skips to D right away. This is not
> intended here. Turn the command whose failure is to be ignored into a
> compound command to ensure it is the only one that is allowed to fail.
> 
> Signed-off-by: Johannes Sixt <j6t@kdbg.org>
> ---
>  t/t3920-crlf-messages.sh | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
> index 4c661d4d54..a58522c163 100755
> --- a/t/t3920-crlf-messages.sh
> +++ b/t/t3920-crlf-messages.sh
> @@ -12,7 +12,7 @@ create_crlf_ref () {
>  	cat >.crlf-orig-$branch.txt &&
>  	cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
>  	grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&
> -	grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
> +	{ grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true; } &&
>  	LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
>  	test_tick &&
>  	hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) &&
> 

Thank you for making that function more robust.

Philippe.
Ævar Arnfjörð Bjarmason Nov. 22, 2022, 10:24 p.m. UTC | #4
On Mon, Nov 21 2022, Johannes Sixt wrote:

> It is customary to write `A || true` to ignore a potential error exit of
> command A. But when we have a sequence `A && B && C || true && D`, then
> a failure of any of A, B, or C skips to D right away. This is not
> intended here. Turn the command whose failure is to be ignored into a
> compound command to ensure it is the only one that is allowed to fail.

> Signed-off-by: Johannes Sixt <j6t@kdbg.org>
> ---
>  t/t3920-crlf-messages.sh | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
> index 4c661d4d54..a58522c163 100755
> --- a/t/t3920-crlf-messages.sh
> +++ b/t/t3920-crlf-messages.sh
> @@ -12,7 +12,7 @@ create_crlf_ref () {
>  	cat >.crlf-orig-$branch.txt &&
>  	cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
>  	grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&
> -	grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
> +	{ grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true; } &&
>  	LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
>  	test_tick &&
>  	hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) &&

Any reason not to make this:

	-       grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
	+       sed -ne '/Body/p' <.crlf-message-$branch.txt >.crlf-body-$branch.txt &&

?

We usually use that for "grep when we don't care about the exit
code". But maybe some CRLF concerns in this code don't allow it (I only
tested this on *nix).
Johannes Sixt Nov. 22, 2022, 10:37 p.m. UTC | #5
Am 22.11.22 um 23:24 schrieb Ævar Arnfjörð Bjarmason:
> On Mon, Nov 21 2022, Johannes Sixt wrote:
>> -	grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
>> +	{ grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true; } &&
> 
> Any reason not to make this:
> 
> 	-       grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
> 	+       sed -ne '/Body/p' <.crlf-message-$branch.txt >.crlf-body-$branch.txt &&
> 
> ?

Yes: I have tested my version, but not this one.

-- Hannes
Ævar Arnfjörð Bjarmason Nov. 22, 2022, 10:57 p.m. UTC | #6
On Tue, Nov 22 2022, Johannes Sixt wrote:

> Am 22.11.22 um 23:24 schrieb Ævar Arnfjörð Bjarmason:
>> On Mon, Nov 21 2022, Johannes Sixt wrote:
>>> -	grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
>>> +	{ grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true; } &&
>> 
>> Any reason not to make this:
>> 
>> 	-       grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
>> 	+       sed -ne '/Body/p' <.crlf-message-$branch.txt >.crlf-body-$branch.txt &&
>> 
>> ?
>
> Yes: I have tested my version, but not this one.

I don't find that too surprising, as unless there's a discussion of "I
tried xyz, but it didn't work, so..." a submitted patch is unlikely to
have tried various alternatives for such a trivial fix, but just gone
with whatever the author tried first.

But in case it wasn't clear, the implied suggestion is that unless there
is a good reason to introduce a pattern of:

	 { <cmd> in >out || true; } &&

That we should use another suitable command with the simpler use of:

	 <cmd2> <in >out &&

If the result is equivalent, as subsequent maintainers won't need to
puzzle over the seemingly odd pattern.

We have that "sed -n -e" in somewhat wide use:

	$ git grep 'sed (-n -e|-ne).*/p.*&&' | wc -l
	54

The only existing occurance of this "grep but ignore the exit code" I
could find was:

	t/t9001-send-email.sh:  { grep '^X-Mailer:' out || :; } >mailer &&

For which we can also:

	-       { grep '^X-Mailer:' out || :; } >mailer &&
	+       sed -ne '/^X-Mailer:/p' <out >mailer &&

And which I'd think would be great to have in a re-roll, i.e. "here's
these two cases where a grep-but-dont-care-about-the-exit-code could be
replaced by sed -ne".

But if re-testing this is tedious etc. I don't mind if it goes in as-is,
but then I'd think we could safely emulate the t9001-send-email.sh
pattern of using ":" instead of "true"; we don't need to invoke another
process just to ignore the exit code.
Junio C Hamano Nov. 23, 2022, 12:55 a.m. UTC | #7
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> We have that "sed -n -e" in somewhat wide use:
>
> 	$ git grep 'sed (-n -e|-ne).*/p.*&&' | wc -l
> 	54
>
> The only existing occurance of this "grep but ignore the exit code" I
> could find was:
>
> 	t/t9001-send-email.sh:  { grep '^X-Mailer:' out || :; } >mailer &&
>
> For which we can also:
>
> 	-       { grep '^X-Mailer:' out || :; } >mailer &&
> 	+       sed -ne '/^X-Mailer:/p' <out >mailer &&
>
> And which I'd think would be great to have in a re-roll, i.e. "here's
> these two cases where a grep-but-dont-care-about-the-exit-code could be
> replaced by sed -ne".
>
> But if re-testing this is tedious etc. I don't mind if it goes in as-is,
> but then I'd think we could safely emulate the t9001-send-email.sh
> pattern of using ":" instead of "true"; we don't need to invoke another
> process just to ignore the exit code.

Let's leave all of the above (mostly good ideas) for "after the dust
settles" clean-up.

If sed is much slower than grep (for such a small string use case,
start-up cost of a process would dwarf everybody else), "grep || :"
might be justifiable, but other than that I do not think of a good
reason why we might favor "grep || :" offhand over "sed -ne //p".
diff mbox series

Patch

diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
index 4c661d4d54..a58522c163 100755
--- a/t/t3920-crlf-messages.sh
+++ b/t/t3920-crlf-messages.sh
@@ -12,7 +12,7 @@  create_crlf_ref () {
 	cat >.crlf-orig-$branch.txt &&
 	cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
 	grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&
-	grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
+	{ grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true; } &&
 	LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
 	test_tick &&
 	hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) &&