Fundamentals 17 min read

Master Linux Command-Line Arguments: argc, argv, getopt, and getopt_long Explained

This guide explains how Linux programs receive command‑line arguments using argc and argv, demonstrates parsing techniques with manual loops, getopt, getopt_long, and getopt_long_only, and provides complete C code examples with expected outputs and common pitfalls.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master Linux Command-Line Arguments: argc, argv, getopt, and getopt_long Explained

argc and argv

When a Linux program starts, the main function receives int argc (the number of command‑line arguments) and char *argv[] (an array of strings, each representing one argument). argv[0] is the program name; the remaining elements hold the user‑supplied parameters.

int main(int argc, char *argv[])
{
    // argc: count of command‑line arguments
    // argv: array of argument strings, terminated by a NULL pointer
}

Example that prints the count and each argument:

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("argc=%d
", argc);
    for (int i = 0; i < argc; i++) {
        printf("argv[%d]: %s
", i, argv[i]);
    }
    return 0;
}

Running ./prog arg1 arg2 arg3 yields:

argc=4
argv[0]: ./prog
argv[1]: arg1
argv[2]: arg2
argv[3]: arg3
argc/argv relationship diagram
argc/argv relationship diagram

Manual option parsing

A simple loop can skip argv[0] and examine each argument. If an argument starts with -, a switch statement handles known options:

int c;
while (--argc > 0 && (*++argv)[0] == '-') {
    while ((c = *++argv[0])) {
        switch (c) {
            case 'a': /* handle -a */ break;
            case 'b': /* handle -b */ break;
            default:  fprintf(stderr, "illegal option %c
", c);
        }
    }
}

Using getopt

The GNU library provides getopt to simplify short‑option parsing. Its prototype is:

#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);
optstring

defines which options are accepted and whether they require an argument ( : for required, :: for optional). Example:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int opt;
    const char *optstring = "ab:c::"; // a: no arg, b: requires arg, c: optional arg
    while ((opt = getopt(argc, argv, optstring)) != -1) {
        switch (opt) {
            case 'a': printf("-a detected
"); break;
            case 'b': printf("-b arg = %s
", optarg); break;
            case 'c': printf("-c arg = %s
", optarg ? optarg : "(none)"); break;
            case '?': fprintf(stderr, "unknown option
"); break;
        }
    }
    return 0;
}

Parsing long options with getopt_long

getopt_long

extends getopt to support GNU‑style long options (e.g., --help). Its signature is:

#include <getopt.h>
int getopt_long(int argc, char * const argv[], const char *optstring,
                const struct option *longopts, int *longindex);

The struct option describes each long option:

struct option {
    const char *name;   // option name without leading '--'
    int         has_arg; // no_argument, required_argument, optional_argument
    int        *flag;   // if non‑NULL, set *flag to val and return 0
    int         val;    // value to return or store in *flag
};

Example definition and usage:

#include <stdio.h>
#include <getopt.h>
int main(int argc, char *argv[])
{
    static struct option long_opts[] = {
        {"reqarg", required_argument, NULL, 'r'},
        {"optarg", optional_argument, NULL, 'o'},
        {"noarg",  no_argument,       NULL, 'n'},
        {NULL, 0, NULL, 0}
    };
    int opt, option_index = 0;
    while ((opt = getopt_long(argc, argv, "a::b:c:d", long_opts, &option_index)) != -1) {
        printf("opt = %c  optarg = %s  optind = %d  argv[optind] = %s  option_index = %d
",
               opt, optarg, optind, argv[optind], option_index);
    }
    return 0;
}

getopt_long_only

getopt_long_only

behaves like getopt_long but also treats a single dash followed by a word (e.g., -help) as a long option when it matches an entry in longopts. This allows mixed short/long styles.

Comprehensive example

The program below demonstrates a robust argument parser that supports short and long options, prints a usage message, and handles errors gracefully.

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <sys/param.h>

#define ETHCHECKD_VERSION "1.1"

int delay_up = 0;
char *interface = "eth0";

void usage(char *p) {
    if (strrchr(p, '/'))
        p = strchr(p, '/') + 1;
    printf("%s [options]
"
           "   -i --iface=IFACE          Specify ethernet interface (%s)
"
           "   -d --delay-up=SECS       Specify delay time (%d)
"
           "   -h --help                Show this help
"
           "   -v --version             Show version
",
           p, interface, delay_up);
}

void parse_args(int argc, char *argv[]) {
    static struct option long_options[] = {
        {"iface",      required_argument, 0, 'i'},
        {"delay-up",   required_argument, 0, 'd'},
        {"help",       no_argument,       0, 'h'},
        {"version",    no_argument,       0, 'v'},
        {0, 0, 0, 0}
    };
    int opt, option_index = 0;
    while ((opt = getopt_long(argc, argv, "i:d:hv", long_options, &option_index)) != -1) {
        switch (opt) {
            case 'i':
                interface = strdup(optarg);
                printf("interface %s
", interface);
                break;
            case 'd':
                delay_up = atoi(optarg);
                printf("delay_up %d
", delay_up);
                break;
            case 'h':
                usage(argv[0]);
                break;
            case 'v':
                printf("peng %s
", ETHCHECKD_VERSION);
                break;
            default:
                fprintf(stderr, "Unknown parameter.
");
                exit(1);
        }
    }
}

int main(int argc, char *argv[]) {
    parse_args(argc, argv);
    return 0;
}

Typical invocations

Short options: ./param -i eth3 -d 15 prints the selected interface and delay.

Long options: ./param --iface eth3 --delay-up 15 produces the same result.

Help: ./param -h or ./param --help displays the usage message.

Version: ./param -v or ./param --version shows the program version.

This example shows how to combine getopt_long with a custom usage function, handle missing arguments, and report unknown options, providing a solid template for building robust command‑line tools in C.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Ccommand-lineargcargvgetoptgetopt_long
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.