Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Satoru Takeuchi
Satoru Takeuchi

Posted on

     

Various Things About Command-line Arguments for Linux Processes

Introduction

When you execute a command like "foo bar baz", the command-line arguments are typically "foo", "bar", and "baz". Although you might think that the arguments are only "bar" and "baz", this is the definition anyway.

In C and C++, command-line arguments can be referenced from theargv array argument of themain function in the program. In the example above, the executable name is stored inargv[0]. The "bar" after that is inargv[1], and "baz" is inargv[2]. The variable equivalent to argv is "$0","$1","$2"... in shell scripts,sys.argv in Python, andos.Args in Go, etc. However, scripts such as shell scripts and Python scripts do not directly expose command-line arguments like C, but show slightly modified ones. This will be discussed later.

About the first element of command-line arguments

The first element of command-line arguments (hereafter referred to asargv[0]) conventionally contains the name of the executable. When executing a program, regardless of the language in which the program is written, theexecve() system call shown below is eventually called, specifying the program's executable name in the pathname argument and the command-line arguments in theargv argument.

intexecve(constchar*pathname,char*constargv[],char*constenvp[]);
Enter fullscreen modeExit fullscreen mode

At this time, following the convention, the same value is specified for pathname andargv[0].

When would you setargv[0] to something other than the name of the executable? For example, when bash is a login shell,argv[0] is not bash but rather "-bash" with a "-" at the beginning. This allows bash to know whether it is a login shell at the time of execution, and to branch its processing accordingly (such as changing the configuration file to be loaded). We will actually verify the value ofargv[0] for bash in the next section.

When executing a program, if the executable is run through an interpreter like a bash script, the interpreter's executable name, not the script name, is stored inargv[0]. For example, if there is a bash script called "test.sh", when executing "./test.sh",argv[0] is the executable name of bash, and "./test.sh" is stored inargv[1]. However, this is hard to handle for programmers. So in bash, you can accessargv[0] with "$0" andargv[1] with "$1". We will actually verify this in a later section as well.

Verifying the values of a process's command-line arguments using procfs

The command-line arguments of each process can be referenced from/proc/<pid>/cmdline. For example, on the Linux machine where the author is currently logged in via ssh, the command-line arguments forrsyslogd, which collects system logs, were as follows:

sat@tea:~$pgrep rsyslogd568sat@tea:~$cat /proc/568/cmdline/usr/sbin/rsyslogd-n-iNONEsat@tea:~
Enter fullscreen modeExit fullscreen mode

The output looks a bit odd. A command-option-like string is connected after the executable-name-like string "/usr/sbin/rsyslogd". Moreover, there is no newline before the next prompt. This is not because the/proc/<pid>/cmdline outputs all arguments without any delimiters such as " " by design. In fact, each argument is separated by a null character (a byte with a value of 0, or "\0" in C) and bash does not display the null character on the screen. We can use binary dump tools likehexdump to confirm this behavior.

$hexdump-c /proc/568/cmdline0000000   /   u   s   r   /   s   b   i   n   /   r   s   y   s   l   o0000010   g   d  \0   -   n  \0   -   i   N   O   N   E  \0           000001d
Enter fullscreen modeExit fullscreen mode

Let's take a look at theargv[0] of bash instances on the system. The last field of theps ax output shows the command-line arguments separated by spaces, so we'll use this to list the existing bash instances on the system.

sat@tea:~$ps ax |grepbash   5239 pts/3    Ss+    0:00 /usr/bin/bash --init-file /home/sat/.vscode-server/bin/74b1f979648cc44d385a2286793c226e611f59e7/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh   8725 pts/4    Ss     0:00 -bash   8907 pts/4    S      0:00 /bin/bash ./test.sh   8909 pts/4    S      0:00 /bin/bash ./test.sh   8929 pts/4    S+     0:00 grep --color=auto bashfor p ax
Enter fullscreen modeExit fullscreen mode

We can see that the processes with pid 5239, 8725, 8907, and 8909 are bash instances. Among them, the process with pid=8725, where the first character ofargv[0] is "-", is the login shell where the author is running the above commands.

Thus, in reality,argv[0] is "/usr/sbin/rsyslogd",argv[1] is "-n", andargv[2] is "-iNONE".

Let's also take a look at an example of a bash script. The script we'll use here outputs "$0" and then sleeps indefinitely.

sat@tea:~$cattest.sh#!/bin/bashecho $0sleep infinitysat@tea:~$./test.shfg./test.sh #Output of`$0`^Z[2]+  Stopped                 ./test.shsat@tea:~$bg[2]+ ./test.sh &sat@tea:~$hexdump-c /proc/8909/cmdline0000000   /   b   i   n   /   b   a   s   h  \0   .   /   t   e   s   t0000010   .   s   h  \0                                               0000014
Enter fullscreen modeExit fullscreen mode

While the value of "$0" is the script name "./test.sh", the value ofargv[0] is "/bin/bash", and the script name is inargv[1]. This means that although it appears to the user as if they are directly executing the "./test.sh" file, the actual program running is bash. Bash interprets and executes the script, mappingargv[1] and beyond to $0 and later variables within the program.

Differences between the command name and command line arguments held by the kernel

Please note that theargv[0] mentioned in this article, which "usually contains the executable file name," is different from the command name seen by the kernel, which is displayed by commands likeps. For more information on the command name from the kernel's perspective, please refer to the following article.

https://dev.to/satorutakeuchi/command-name-from-the-perspective-of-the-linux-kernel-257l

The command name seen by the kernel is the "first 15 bytes of the basename of the executable file name" and is different fromargv[0].

Conclusion

I hope this article will reduce confusion about command names, executable file names, command line arguments, and the command line arguments that can be referenced from within the program's source code.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

One of the Rook's maintainers, ex-Linux kernel developer, developing a storage system based on Ceph on top of Kubernetes.
  • Location
    Japan
  • Work
    Software engineer at Cybozu.inc
  • Joined

More fromSatoru Takeuchi

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp