SQLite Forum

Run /usr/bin/sqlite3 -help, return value is not 0
Login

Run /usr/bin/sqlite3 -help, return value is not 0

(1) By gordonwwang on 2024-01-23 06:14:56 [link] [source]

After sqlite is installed, run /usr/bin/sqlite3 -help. The command is successfully executed, and related information is displayed. But the echo $? The return value you see is not 0, but 1. This does not comply with Unix rules, does it need fixing?

(2) By Stephan Beal (stephan) on 2024-01-23 10:46:09 in reply to 1 [link] [source]

This does not comply with Unix rules,

What rules are you referring to? The result code for an application is determined not by the OS, but the developer, and there are two schools of thought on whether invoking help should exit as success or failure.

does it need fixing?

Is the current behavior causing a specific issue for you?

(3) By gordonwwang on 2024-01-23 11:32:00 in reply to 1 [link] [source]

  1. Posix information is as follows:
    An exit code, or sometimes known as a return code, is the code returned to a parent process by an executable. On POSIX systems the standard exit code is 0 for success and any number from 1 to 255 for anything else.
    
    Is there any other consideration for sqlite to return non-0 on successful execution?

In my opinion, if there is no better reason, should we follow the default or more widely used rules (although this is the OS function return rule, but the principle should be the same)?

  1. We need to check whether each command is executed successfully, for example, /usr/bin/sqlite3-help. But executing sqlite3 returned a different value than we expected, leaving me confused, so I came to ask.

By the way, does sqlite have its own specification for the return value of a function or instruction? Could you please provide relevant documents for me to study and refer to

(4) By Stephan Beal (stephan) on 2024-01-23 11:43:03 in reply to 3 [link] [source]

On POSIX systems the standard exit code is 0 for success and any number from 1 to 255 for anything else.

--help being a special case, with the aforementioned two schools of thought on that topic. Some (very probably most) apps treat that as a zero and some don't. The sqlite CLI shell currently treats it as non-zero and we've yet to hear a compelling argument for changing that. We're not against making changes, but we tend to shy away from "change for change's sake."

We need to check whether each command is executed successfully, for example, /usr/bin/sqlite3-help. But executing sqlite3 returned a different value than we expected, leaving me confused, so I came to ask.

Out of curiosity: can you elaborate on the "we" and why "we" are testing for the result code of --help?

By the way, does sqlite have its own specification for the return value of a function or instruction?

The C API has extensive docs on that subject, but the CLI app you're using makes no guarantees about result codes beyond "success" or "fail".

(5.1) By gordonwwang on 2024-01-23 11:59:24 edited from 5.0 in reply to 4 [link] [source]

I read the C API documentation you mentioned. In https://sqlite.org/c3ref/c_abort.html, for example, sqlite return values are defined as follows:

#define SQLITE_OK           0   /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR        1   /* Generic error */

As you can see here, on successful execution, the return value is 0.

  1. You mentioned that there are two schools, which I can understand. After all, every coin has two sides. But I see that genre A is specified in the C API, but genre B is used in the sqlite3-help instruction. Why is sqlite a product or software that uses two opposing rules at the same time?
  2. Last but not least, for the same directive /usr/bin/sqlite3, /usr/bin/sqlite3 -help returns 1; When /usr/bin/sqlite3-version is executed, 0 is returned. Although the two commands are executed successfully, the return values are different. Why do you use two opposing rules in /usr/bin/sqlite3? Isn't that problematic? You are a sqlite professional and would like to hear your explanation

(6.1) By Stephan Beal (stephan) on 2024-01-23 12:24:03 edited from 6.0 in reply to 5.1 [link] [source]

As you can see here, on successful execution, the return value is 0.

That's the C code API, not the shell application's specification.

Why is sqlite a product or software that uses two opposing rules at the same time?

It does not. Whether or not "--help" is "success" or "failure" is a matter of opinion. Whoever initially wrote the code in the sqlite shell app was (and may be still be) of the opinion that --help should result in a non-zero exit code. Being a matter of opinion, there is neither a correct nor incorrect answer.

Conversely, whether or not any give C API succeeds or fails is a matter of technical fact, not opinion, and every C API which returns a non-void value has specific, documented success and error results.

Isn't that problematic?

No, it's not. You have yet to point out anything which has been broken by its current (and long-standing) behavior.

You're arguing a matter of principle, but getting the current behavior changed requires a compelling technical argument. If it demonstrably breaks something, a change will be considered. If it's not breaking things, it does not need to be changed because change often leads to new downstream breakage.

Edit: Application result codes (the code returned by the sqlite3 CLI shell application, as opposed to its C library) are primarily for use by shell scripts and --help is a feature for interactive use with a user. Interactive shell users do not check for the result of $? after every application invocation, and certainly not after invoking --help (except, as in your case, when they're simply curious about what its result code is). Script code doesn't invoke --help, so its result code is largely irrelevant.

(7) By gordonwwang on 2024-01-23 12:45:03 in reply to 6.1 [link] [source]

  1. I still don't understand, executing the same command /usr/bin/sqlite3, the -version and -help arguments return 0 and 1 respectively on successful execution. Is there any theory or documentation to support developers doing this? If yes, I would appreciate it if you could provide me with the link for my study
  2. We are the maintainers of the distribution of the operating system, and we care about whether each instruction can be successfully executed on the OS. When instructions are executed incorrectly, they need to be fixed. So we are confused about the false report that sqlite3-help is finished.
  3. We should not restrict the behavior of shell users, it is too difficult, we just need to regulate our own tools. When the instruction succeeds, return 0.

(8) By Stephan Beal (stephan) on 2024-01-23 12:51:44 in reply to 6.1 [link] [source]

It does not. Whether or not "--help" is "success" or "failure" is a matter of opinion. Whoever initially wrote the code in the sqlite shell app was (and may be still be) of the opinion that --help should result in a non-zero exit code.

That developer has since changed their opinion and --help now, in the trunk version, returns 0. This will be part of the 3.46 release.

$ ./sqlite3 --help 2>/dev/null; echo $?
0
$ ./sqlite3 --version
3.46.0 2024-01-22 14:01:07 4dc00f577632c7b13135505007804d42a12f81a9ebd58d4c380727256b05alt1 (64-bit)

(9) By Warren Young (wyoung) on 2024-01-23 15:24:44 in reply to 8 [source]

Not to undermine this decision, but this thread inspired me to write a program to collect stats on what other programs do in this situation, and as it turns out, the current sqlite3 shell behavior puts it among the (thin) majority on my macOS 14 system, where I got this result for /usr/bin:

Status	Count
0	209
1	283
2	78
255	54
64	29
13	6
25	6
124	3
3	3
5	3
205	2
75	2
10	1
127	1
201	1
4	1
6	1

In aggregate, the ratio is 2.27:1 in favor of nonzero exit status on this system.

The data differs on the Ubuntu 22.04 LTS box hosting that program's repository. 0 as exit for --help is much more popular, with 4.74:1 in favor of it. Even so, it's hardly the universal that the OP would hope for.

(10) By Richard Hipp (drh) on 2024-01-23 15:34:46 in reply to 9 [link] [source]

This is a very interesting result, Warren. Thanks for publishing it.

(11) By Nuno Cruces (ncruces) on 2024-01-24 08:40:30 in reply to 9 [link] [source]

Sorry to interject. I've just been asked to change the help output of a tool from stderr to stdout. Do you happen to know what's more common?

(13.1) By Warren Young (wyoung) on 2024-01-24 09:09:52 edited from 13.0 in reply to 11 [link] [source]

Part of my purpose in publishing my testing script was so others can take it and modify it to their own purposes.

But okay, I'll do it for you in this instance, giving this result for one1 macOS 14 system here:

STDOUT Status   Count
0               152
1               56
124             11
64              6
2               2
201             1
205             1
3               1
5               1

STDERR Status   Count
0               49
1               229
2               78
255             54
64              23
25              6
5               2
75              2
10              1
127             1
205             1
3               1
4               1
6               1

That version is now tip-of-trunk.


  1. ^ Not the same one as in the post up-thread, explaining the different results when you add the two sets of results together. Another reason to test on your own systems.

(17) By Nuno Cruces (ncruces) on 2024-01-24 11:08:44 in reply to 13.1 [link] [source]

Really sorry, I missed the link to the source code for the script. I could've totally done this myself. Thanks!

(14.1) By gordonwwang on 2024-01-24 09:36:26 edited from 14.0 in reply to 11 [link] [source]

Inspired by Warren, I wrote a program that counted the return value after bin --help in /usr/bin for OpenCloudOS and fedora (both Linux operating systems). As you can see, return 0 still dominates. In OpenCloudOS, 80%; In fedora, it accounts for 78%. I hope my data and Warren's can help you.

OpenCloudOS:

  Count Return value
    896 0
    161 1
      5 100
      1 12
      1 16
      2 19
     17 2
      1 22
     18 255
      3 3
      1 31
      1 4
      3 64
      1 66
      1 8
      3 9

fedora:

  Count Return value
   1288 0
    248 1
      5 100
      1 -11
      1 12
      1 16
      2 19
     63 2
      1 22
     29 255
      2 3
      2 4
      7 64
      1 66
      3 9
      2 99

(15) By Warren Young (wyoung) on 2024-01-24 09:41:22 in reply to 14.1 [link] [source]

If we had the program's source code, we might understand how you can get a return value of -11 on Fedora.

(16.1) By gordonwwang on 2024-01-24 09:50:00 edited from 16.0 in reply to 15 [link] [source]

Sure, the python code is as follows: Inspired by you, I added check for support --help when traversing bin files

import os
import subprocess
import re

# Get all /usr/bin
usr_bin_path = "/usr/bin"
executable_files = [os.path.join(usr_bin_path, f) for f in os.listdir(usr_bin_path) if os.path.isfile(os.path.join(usr_bin_path, f)) and os.access(os.path.join(usr_bin_path, f), os.X_OK)]

with open("res.log", "w") as log_file:
    log_file.write("")

for exe_file in executable_files:
    try:
        # exec --help and get return
        result = subprocess.run([exe_file, "--help"], capture_output=True, timeout=5, text=True)
        output = result.stdout.lower() + result.stderr.lower()
        return_code = result.returncode

        # Check if --help is supported
        help_keywords = ["usage", "options", "help"]
        supports_help = any(keyword in output for keyword in help_keywords)

        # if support --help, record it
        if supports_help:
            with open("res.log", "a") as log_file:
                log_file.write(f"{exe_file} {return_code}\n")

    except Exception as e:
        print(f"Error while processing {exe_file}: {e}")

(24) By anonymous on 2024-01-25 07:41:07 in reply to 16.1 [link] [source]

Which one return -11 in fedora? Why?

(25) By Chris Locke (chrisjlocke1) on 2024-01-25 10:40:20 in reply to 24 [link] [source]

Because -4 and -9 were already used?

(27) By Rowan Worth (sqweek) on 2024-01-26 00:43:15 in reply to 24 [link] [source]

The python docs say:

returncode

Exit status of the child process. Typically, an exit status of 0 indicates that it ran successfully.

A negative value -N indicates that the child was terminated by signal N (POSIX only).

ie. -11 means something segfaulted on --help XD

Note that the exit status in posix is an unsigned 8-bit integer so applications themselves cannot exit with a negative status. Typically in the shell environment, termination via signal is indicated by an exit code of 128+N where N is the signal number so this reduces the "usable space" to 7-bits.

Many misguided application programmers do try to exit(-1) and this manifests in the shell as an exit code of 255.

(26) By Rowan Worth (sqweek) on 2024-01-26 00:32:56 in reply to 11 [link] [source]

Every tool I've ever written writes help output to stderr and exits non-zero.

Having worked with a lot of software environments that do heavy computation and pump gigabytes of data through unix pipelines, I now consider stdout a sacred data stream and put any kind of message that should be seen by a human on stderr.

I lost count of how many times I tracked processing failures back to some process somewhere emitting error messages to stdout, corrupting the data stream. Java apps were the worst offenders, the JVM has/had some wild edge cases that are logged to stdout rather than stderr...

As for the exit status, it's true that foo --help represents a "success" in that it was asked to output documentation and it did, however it's not a success in the sense that it hasn't accomplished any kind of useful processing. Where the exit code most matters is in scripting, eg. consider a simple contrived example:

#!/bin/sh

for file in ./*; do
    if grep -q "$@" "$file"; then
        rm "$file"
    fi
done

We check files in the current directory and delete those whose content matches a user-supplied pattern. Using grep "$@" allows users to control how the pattern is interpreted (eg. -E or -F or -x) or even invert the behaviour with -v.

However in a world where grep --help exits with code 0¹, if a user (or yourself a few months later) naïvely tries to run this script with --help to learn how to use it, we end up deleting everything in the current directory without actually checking any file contents.

There are other problems here:

  • as mentioned elsewhere in the thread, --version is in a similar boat where it requests the tool to produce completely different output to normal (and some portable scripts do rely on --version which typically does exit 0)
  • it's not a strong use case for a script, rm $(grep -l ... *) will almost certainly do the job
  • arguably the script not handling --help to provide its own documentation is a bug

So it's not a strong argument, however this argument-chaining approach is convenient for building useful tools without excessive boilerplate/manual argument parsing and demonstrates one reason it is desirable for tools to exit abnormally when asked to behave abnormally.

¹ turns out that is this world for many of us -- GNU grep --help exits zero while BSD grep --help exits non-zero (although I suspect that's because BSD grep doesn't actually recognise --help and invokes its "dump usage summary and exit" function)

(12.1) By Nuno Cruces (ncruces) on 2024-01-24 08:58:14 edited from 12.0 in reply to 9 [link] [source]

Deleted

(18) By Anton Dyachenko (ahtoh_) on 2024-01-25 01:14:42 in reply to 8 [link] [source]

The reasoning behind zero code is quite obvious and intuitive and additionally provided here by OP. I did my homework and searched on the internet and even asked llm but I couldn't find any description to support returning non-zero code. Out of academic interest could you provide links or reasoning that were used back in time to program it that way?

(19) By Larry Brasfield (larrybr) on 2024-01-25 02:43:47 in reply to 18 [link] [source]

reasoning that were used back in time to program it that way?

(Answering for myself, not the askee.)

Here is a pattern I have seen in some command-line tools for which I have quickly written the source or touched source from others.

Amidst option processing, misuse of options or malformmed options cause a function to be called (or even jumped to) which could be named (or labeled) blat_help_and_quit_with_error.

It is easy, perhaps even lazy, to just run such code for the --help argument (or any semblance of it), and to rationalize this by thinking "A help request is always interactive anyway, so who cares about an error return?" (Until I saw this thread, I never imagined that anybody would intentionally test the exit code for a --help invocation.1)

I am a devout believer in the Unix way, the "Silence is Golden" convention, and the proper use of process exit codes. Yet, even with that attitude, and knowing that a "correct" help plea is not an error, I have been willing to overlook that teensy foible because I had never imagined it mattered. I confess not trying very hard to imagine such.


  1. ^ Imagine somebody so perverse as to type "ls --help || echo 'That is not a proper help request!'"

(20) By gordonwwang on 2024-01-25 03:08:39 in reply to 19 [link] [source]

In reply # 8, your colleague mentioned that --help returning 0 will come online in 3.46. (For the transcript of my communication with Stephan Beal, see the first eight replies.)

Does your reply mean that this change will not be available in 3.46?

(21) By Stephan Beal (stephan) on 2024-01-25 03:13:14 in reply to 20 [link] [source]

Does your reply mean that this change will not be available in 3.46?

It's already in the trunk, which is what will eventually be 3.46. It will not be back-ported to 3.45, even though there may be more 3.45.X patch releases before the 3.46 release, because patch releases are only intended for bug fixes (which this is not).

(23) By gordonwwang on 2024-01-25 03:20:51 in reply to 21 [link] [source]

Thank you, Stephan.

(22) By Larry Brasfield (larrybr) on 2024-01-25 03:17:14 in reply to 20 [link] [source]

My reply is no more than a response to the post it nominally replies to and the question quoted.

You could infer that I might have not acted on the change request, but to me it is of too little importance to consider persuading Stephan that his change should be undone.

Still, I have imagined, upon the 3.46 release, hearing from some other folks that their testing for an error exit with --help has been broken. I am unsure whether my sympathy lies more with them than with the wanna-see-0-exit crowd.