Write a shell in C
https://brennan.io/2015/01/16/write-a-shell-in-c/
Tutorial - Write a Shell in C - Stephen Brennan
2015-01-16
Stephen Brennan
<div><div>
 
<p><em>Stephen Brennan • 16 January 2015</em></p><p>It’s easy to view yourself as “not a <em>real</em> programmer.” There are programs out
there that everyone uses, and it’s easy to put their developers on a pedestal.
Although developing large software projects isn’t easy, many times the basic
idea of that software is quite simple. Implementing it yourself is a fun way to
show that you have what it takes to be a real programmer. So, this is a
walkthrough on how I wrote my own simplistic Unix shell in C, in the hopes that
it makes other people feel that way too.</p>
<p>The code for the shell described here, dubbed <code>lsh</code>, is available on
<a href="https://github.com/brenns10/lsh">GitHub</a>.</p>
<p><strong>University students beware!</strong> Many classes have assignments that ask you to
write a shell, and some faculty are aware of this tutorial and code. If you’re
a student in such a class, you shouldn’t copy (or copy then modify) this code
without permission. And even then, I would <a href="/2016/03/29/dishonesty/">advise</a> against heavily relying on this tutorial.</p>
<h2>Basic lifetime of a shell</h2>
<p>Let’s look at a shell from the top down. A shell does three main things in its
lifetime.</p>
<ul>
 <li><strong>Initialize</strong>: In this step, a typical shell would read and execute its
configuration files. These change aspects of the shell’s behavior.</li>
 <li><strong>Interpret</strong>: Next, the shell reads commands from stdin (which could be
interactive, or a file) and executes them.</li>
 <li><strong>Terminate</strong>: After its commands are executed, the shell executes any
shutdown commands, frees up any memory, and terminates.</li>
</ul>
<p>These steps are so general that they could apply to many programs, but we’re
going to use them for the basis for our shell. Our shell will be so simple that
there won’t be any configuration files, and there won’t be any shutdown command.
So, we’ll just call the looping function and then terminate. But in terms of
architecture, it’s important to keep in mind that the lifetime of the program is
more than just looping.</p>
<div><pre><code>int main(int argc, char **argv)
{
 // Load config files, if any.
 // Run command loop.
 lsh_loop();
 // Perform any shutdown/cleanup.
 return EXIT_SUCCESS;
}
</code></pre></div>
<p>Here you can see that I just came up with a function, <code>lsh_loop()</code>, that will
loop, interpreting commands. We’ll see the implementation of that next.</p>
<h2>Basic loop of a shell</h2>
<p>So we’ve taken care of how the program should start up. Now, for the basic
program logic: what does the shell do during its loop? Well, a simple way to
handle commands is with three steps:</p>
<ul>
 <li><strong>Read</strong>: Read the command from standard input.</li>
 <li><strong>Parse</strong>: Separate the command string into a program and arguments.</li>
 <li><strong>Execute</strong>: Run the parsed command.</li>
</ul>
<p>Here, I’ll translate those ideas into code for <code>lsh_loop()</code>:</p>
<div><pre><code>void lsh_loop(void)
{
 char *line;
 char **args;
 int status;
 do {
 printf("&gt; ");
 line = lsh_read_line();
 args = lsh_split_line(line);
 status = lsh_execute(args);
 free(line);
 free(args);
 } while (status);
}
</code></pre></div>
<p>Let’s walk through the code. The first few lines are just declarations. The
do-while loop is more convenient for checking the status variable, because it
executes once before checking its value. Within the loop, we print a prompt,
call a function to read a line, call a function to split the line into args, and
execute the args. Finally, we free the line and arguments that we created
earlier. Note that we’re using a status variable returned by <code>lsh_execute()</code> to
determine when to exit.</p>
<h2>Reading a line</h2>
<p>Reading a line from stdin sounds so simple, but in C it can be a hassle. The
sad thing is that you don’t know ahead of time how much text a user will enter
into their shell. You can’t simply allocate a block and hope they don’t exceed
it. Instead, you need to start with a block, and if they do exceed it,
reallocate with more space. This is a common strategy in C, and we’ll use it to
implement <code>lsh_read_line()</code>.</p>
<div><pre><code>#define LSH_RL_BUFSIZE 1024
char *lsh_read_line(void)
{
 int bufsize = LSH_RL_BUFSIZE;
 int position = 0;
 char *buffer = malloc(sizeof(char) * bufsize);
 int c;
 if (!buffer) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 while (1) {
 // Read a character
 c = getchar();
 // If we hit EOF, replace it with a null character and return.
 if (c == EOF || c == '\n') {
 buffer[position] = '\0';
 return buffer;
 } else {
 buffer[position] = c;
 }
 position++;
 // If we have exceeded the buffer, reallocate.
 if (position &gt;= bufsize) {
 bufsize += LSH_RL_BUFSIZE;
 buffer = realloc(buffer, bufsize);
 if (!buffer) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 }
 }
}
</code></pre></div>
<p>The first part is a lot of declarations. If you hadn’t noticed, I prefer to
keep the old C style of declaring variables before the rest of the code. The
meat of the function is within the (apparently infinite) <code>while (1)</code> loop. In
the loop, we read a character (and store it as an <code>int</code>, not a <code>char</code>, that’s
important! EOF is an integer, not a character, and if you want to check for it,
you need to use an <code>int</code>. This is a common beginner C mistake.). If it’s the
newline, or EOF, we null terminate our current string and return it. Otherwise,
we add the character to our existing string.</p>
<p>Next, we see whether the next character will go outside of our current buffer
size. If so, we reallocate our buffer (checking for allocation errors) before
continuing. And that’s really it.</p>
<p>Those who are intimately familiar with newer versions of the C library may note
that there is a <code>getline()</code> function in <code>stdio.h</code> that does most of the work we
just implemented. To be completely honest, I didn’t know it existed until after
I wrote this code. This function was a GNU extension to the C library until
2008, when it was added to the specification, so most modern Unixes should have
it now. I’m leaving my existing code the way it is, and I encourage people to
learn it this way first before using <code>getline</code>. You’d be robbing yourself of a
learning opportunity if you didn’t! Anyhow, with <code>getline</code>, the function
becomes easier:</p>
<div><pre><code>char *lsh_read_line(void)
{
 char *line = NULL;
 ssize_t bufsize = 0; // have getline allocate a buffer for us
 if (getline(&amp;line, &amp;bufsize, stdin) == -1){
 if (feof(stdin)) {
 exit(EXIT_SUCCESS); // We recieved an EOF
 } else {
 perror("readline");
 exit(EXIT_FAILURE);
 }
 }
 return line;
}
</code></pre></div>
<p>This is not 100% trivial because we still need to check for EOF or errors while
reading. EOF (end of file) means that either we were reading commands from a
text file which we’ve reached the end of, or the user typed Ctrl-D, which
signals end-of-file. Either way, it means we should exit successfully, and if
any other error occurs, we should fail after printing the error.</p>
<h2>Parsing the line</h2>
<p>OK, so if we look back at the loop, we see that we now have implemented
<code>lsh_read_line()</code>, and we have the line of input. Now, we need to parse that
line into a list of arguments. I’m going to make a glaring simplification here,
and say that we won’t allow quoting or backslash escaping in our command line
arguments. Instead, we will simply use whitespace to separate arguments from
each other. So the command <code>echo "this message"</code> would not call echo with a
single argument <code>this message</code>, but rather it would call echo with two
arguments: <code>"this</code> and <code>message"</code>.</p>
<p>With those simplifications, all we need to do is “tokenize” the string using
whitespace as delimiters. That means we can break out the classic library
function <code>strtok</code> to do some of the dirty work for us.</p>
<div><pre><code>#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
char **lsh_split_line(char *line)
{
 int bufsize = LSH_TOK_BUFSIZE, position = 0;
 char **tokens = malloc(bufsize * sizeof(char*));
 char *token;
 if (!tokens) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 token = strtok(line, LSH_TOK_DELIM);
 while (token != NULL) {
 tokens[position] = token;
 position++;
 if (position &gt;= bufsize) {
 bufsize += LSH_TOK_BUFSIZE;
 tokens = realloc(tokens, bufsize * sizeof(char*));
 if (!tokens) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 }
 token = strtok(NULL, LSH_TOK_DELIM);
 }
 tokens[position] = NULL;
 return tokens;
}
</code></pre></div>
<p>If this code looks suspiciously similar to <code>lsh_read_line()</code>, it’s because it
is! We are using the same strategy of having a buffer and dynamically expanding
it. But this time, we’re doing it with a null-terminated array of pointers
instead of a null-terminated array of characters.</p>
<p>At the start of the function, we begin tokenizing by calling <code>strtok</code>. It
returns a pointer to the first token. What <code>strtok()</code> actually does is return
pointers to within the string you give it, and place <code>\0</code> bytes at the end of
each token. We store each pointer in an array (buffer) of character
pointers.</p>
<p>Finally, we reallocate the array of pointers if necessary. The process repeats
until no token is returned by <code>strtok</code>, at which point we null-terminate the
list of tokens.</p>
<p>So, once all is said and done, we have an array of tokens, ready to execute.
Which begs the question, how do we do that?</p>
<h2>How shells start processes</h2>
<p>Now, we’re really at the heart of what a shell does. Starting processes is the
main function of shells. So writing a shell means that you need to know exactly
what’s going on with processes and how they start. That’s why I’m going to take
us on a short diversion to discuss processes in Unix-like operating systems.</p>
<p>There are only two ways of starting processes on Unix. The first one (which
almost doesn’t count) is by being Init. You see, when a Unix computer boots,
its kernel is loaded. Once it is loaded and initialized, the kernel starts only
one process, which is called Init. This process runs for the entire length of
time that the computer is on, and it manages loading up the rest of the
processes that you need for your computer to be useful.</p>
<p>Since most programs aren’t Init, that leaves only one practical way for
processes to get started: the <code>fork()</code> system call. When this function is
called, the operating system makes a duplicate of the process and starts them
both running. The original process is called the “parent”, and the new one is
called the “child”. <code>fork()</code> returns 0 to the child process, and it returns to
the parent the process ID number (PID) of its child. In essence, this means
that the only way for new processes is to start is by an existing one
duplicating itself.</p>
<p>This might sound like a problem. Typically, when you want to run a new process,
you don’t just want another copy of the same program – you want to run a
different program. That’s what the <code>exec()</code> system call is all about. It
replaces the current running program with an entirely new one. This means that
when you call <code>exec</code>, the operating system stops your process, loads up the new
program, and starts that one in its place. A process never returns from an
<code>exec()</code> call (unless there’s an error).</p>
<p>With these two system calls, we have the building blocks for how most programs
are run on Unix. First, an existing process forks itself into two separate
ones. Then, the child uses <code>exec()</code> to replace itself with a new program. The
parent process can continue doing other things, and it can even keep tabs on its
children, using the system call <code>wait()</code>.</p>
<p>Phew! That’s a lot of information, but with all that background, the following
code for launching a program will actually make sense:</p>
<div><pre><code>int lsh_launch(char **args)
{
 pid_t pid, wpid;
 int status;
 pid = fork();
 if (pid == 0) {
 // Child process
 if (execvp(args[0], args) == -1) {
 perror("lsh");
 }
 exit(EXIT_FAILURE);
 } else if (pid &lt; 0) {
 // Error forking
 perror("lsh");
 } else {
 // Parent process
 do {
 wpid = waitpid(pid, &amp;status, WUNTRACED);
 } while (!WIFEXITED(status) &amp;&amp; !WIFSIGNALED(status));
 }
 return 1;
}
</code></pre></div>
<p>Alright. This function takes the list of arguments that we created earlier.
Then, it forks the process, and saves the return value. Once <code>fork()</code> returns,
we actually have <em>two</em> processes running concurrently. The child process will
take the first if condition (where <code>pid == 0</code>).</p>
<p>In the child process, we want to run the command given by the user. So, we use
one of the many variants of the <code>exec</code> system call, <code>execvp</code>. The different
variants of <code>exec</code> do slightly different things. Some take a variable number of
string arguments. Others take a list of strings. Still others let you specify
the environment that the process runs with. This particular variant expects a
program name and an array (also called a vector, hence the ‘v’) of string
arguments (the first one has to be the program name). The ‘p’ means that
instead of providing the full file path of the program to run, we’re going to
give its name, and let the operating system search for the program in the path.</p>
<p>If the exec command returns -1 (or actually, if it returns at all), we know
there was an error. So, we use <code>perror</code> to print the system’s error message,
along with our program name, so users know where the error came from. Then, we
exit so that the shell can keep running.</p>
<p>The second condition (<code>pid &lt; 0</code>) checks whether <code>fork()</code> had an error. If so,
we print it and keep going – there’s no handling that error beyond telling the
user and letting them decide if they need to quit.</p>
<p>The third condition means that <code>fork()</code> executed successfully. The parent
process will land here. We know that the child is going to execute the process,
so the parent needs to wait for the command to finish running. We use
<code>waitpid()</code> to wait for the process’s state to change. Unfortunately,
<code>waitpid()</code> has a lot of options (like <code>exec()</code>). Processes can change state in
lots of ways, and not all of them mean that the process has ended. A process
can either exit (normally, or with an error code), or it can be killed by a
signal. So, we use the macros provided with <code>waitpid()</code> to wait until either
the processes are exited or killed. Then, the function finally returns a 1, as
a signal to the calling function that we should prompt for input again.</p>
<h2>Shell Builtins</h2>
<p>You may have noticed that the <code>lsh_loop()</code> function calls <code>lsh_execute()</code>, but
above, we titled our function <code>lsh_launch()</code>. This was intentional! You see,
most commands a shell executes are programs, but not all of them. Some of them
are built right into the shell.</p>
<p>The reason is actually pretty simple. If you want to change directory, you need
to use the function <code>chdir()</code>. The thing is, the current directory is a
property of a process. So, if you wrote a program called <code>cd</code> that changed
directory, it would just change its own current directory, and then terminate.
Its parent process’s current directory would be unchanged. Instead, the shell
process itself needs to execute <code>chdir()</code>, so that its own current directory is
updated. Then, when it launches child processes, they will inherit that
directory too.</p>
<p>Similarly, if there was a program named <code>exit</code>, it wouldn’t be able to exit the
shell that called it. That command also needs to be built into the shell.
Also, most shells are configured by running configuration scripts, like
<code>~/.bashrc</code>. Those scripts use commands that change the operation of the shell.
These commands could only change the shell’s operation if they were implemented
within the shell process itself.</p>
<p>So, it makes sense that we need to add some commands to the shell itself. The
ones I added to my shell are <code>cd</code>, <code>exit</code>, and <code>help</code>. Here are their function
implementations below:</p>
<div><pre><code>/*
 Function Declarations for builtin shell commands:
 */
int lsh_cd(char **args);
int lsh_help(char **args);
int lsh_exit(char **args);
/*
 List of builtin commands, followed by their corresponding functions.
 */
char *builtin_str[] = {
 "cd",
 "help",
 "exit"
};
int (*builtin_func[]) (char **) = {
 &amp;lsh_cd,
 &amp;lsh_help,
 &amp;lsh_exit
};
int lsh_num_builtins() {
 return sizeof(builtin_str) / sizeof(char *);
}
/*
 Builtin function implementations.
*/
int lsh_cd(char **args)
{
 if (args[1] == NULL) {
 fprintf(stderr, "lsh: expected argument to \"cd\"\n");
 } else {
 if (chdir(args[1]) != 0) {
 perror("lsh");
 }
 }
 return 1;
}
int lsh_help(char **args)
{
 int i;
 printf("Stephen Brennan's LSH\n");
 printf("Type program names and arguments, and hit enter.\n");
 printf("The following are built in:\n");
 for (i = 0; i &lt; lsh_num_builtins(); i++) {
 printf(" %s\n", builtin_str[i]);
 }
 printf("Use the man command for information on other programs.\n");
 return 1;
}
int lsh_exit(char **args)
{
 return 0;
}
</code></pre></div>
<p>There are three parts to this code. The first part contains <em>forward
declarations</em> of my functions. A forward declaration is when you declare (but
don’t define) something, so that you can use its name before you define it. The
reason I do this is because <code>lsh_help()</code> uses the array of builtins, and the
arrays contain <code>lsh_help()</code>. The cleanest way to break this dependency cycle is
by forward declaration.</p>
<p>The next part is an array of builtin command names, followed by an array of
their corresponding functions. This is so that, in the future, builtin commands
can be added simply by modifying these arrays, rather than editing a large
“switch” statement somewhere in the code. If you’re confused by the declaration
of <code>builtin_func</code>, that’s OK! I am too. It’s an array of function pointers
(that take array of strings and return an int). Any declaration involving
function pointers in C can get really complicated. I still look up how function
pointers are declared myself!<sup><a href="#fn:1">1</a></sup></p>
<p>Finally, I implement each function. The <code>lsh_cd()</code> function first checks that
its second argument exists, and prints an error message if it doesn’t. Then, it
calls <code>chdir()</code>, checks for errors, and returns. The help function prints a
nice message and the names of all the builtins. And the exit function returns
0, as a signal for the command loop to terminate.</p>
<h2>Putting together builtins and processes</h2>
<p>The last missing piece of the puzzle is to implement <code>lsh_execute()</code>, the
function that will either launch a builtin, or a process. If you’re reading
this far, you’ll know that we’ve set ourselves up for a really simple function:</p>
<div><pre><code>int lsh_execute(char **args)
{
 int i;
 if (args[0] == NULL) {
 // An empty command was entered.
 return 1;
 }
 for (i = 0; i &lt; lsh_num_builtins(); i++) {
 if (strcmp(args[0], builtin_str[i]) == 0) {
 return (*builtin_func[i])(args);
 }
 }
 return lsh_launch(args);
}
</code></pre></div>
<p>All this does is check if the command equals each builtin, and if so, run it.
If it doesn’t match a builtin, it calls <code>lsh_launch()</code> to launch the process.
The one caveat is that <code>args</code> might just contain NULL, if the user entered an
empty string, or just whitespace. So, we need to check for that case at the
beginning.</p>
<h2>Putting it all together</h2>
<p>That’s all the code that goes into the shell. If you’ve read along, you should
understand completely how the shell works. To try it out (on a Linux machine),
you would need to copy these code segments into a file (<code>main.c</code>), and compile
it. Make sure to only include one implementation of <code>lsh_read_line()</code>. You’ll
need to include the following headers at the top. I’ve added notes so that you
know where each function comes from.</p>
<ul>
 <li><code>#include &lt;sys/wait.h&gt;</code>
 <ul>
 <li><code>waitpid()</code> and associated macros</li>
 </ul>
 </li>
 <li><code>#include &lt;unistd.h&gt;</code>
 <ul>
 <li><code>chdir()</code></li>
 <li><code>fork()</code></li>
 <li><code>exec()</code></li>
 <li><code>pid_t</code></li>
 </ul>
 </li>
 <li><code>#include &lt;stdlib.h&gt;</code>
 <ul>
 <li><code>malloc()</code></li>
 <li><code>realloc()</code></li>
 <li><code>free()</code></li>
 <li><code>exit()</code></li>
 <li><code>execvp()</code></li>
 <li><code>EXIT_SUCCESS</code>, <code>EXIT_FAILURE</code></li>
 </ul>
 </li>
 <li><code>#include &lt;stdio.h&gt;</code>
 <ul>
 <li><code>fprintf()</code></li>
 <li><code>printf()</code></li>
 <li><code>stderr</code></li>
 <li><code>getchar()</code></li>
 <li><code>perror()</code></li>
 </ul>
 </li>
 <li><code>#include &lt;string.h&gt;</code>
 <ul>
 <li><code>strcmp()</code></li>
 <li><code>strtok()</code></li>
 </ul>
 </li>
</ul>
<p>Once you have the code and headers, it should be as simple as running <code>gcc -o
main main.c</code> to compile it, and then <code>./main</code> to run it.</p>
<p>Alternatively, you can get the code from
<a href="https://github.com/brenns10/lsh/tree/407938170e8b40d231781576e05282a41634848c">GitHub</a>.
That link goes straight to the current revision of the code at the time of this
writing– I may choose to update it and add new features someday in the future.
If I do, I’ll try my best to update this article with the details and
implementation ideas.</p>
<h2>Wrap up</h2>
<p>If you read this and wondered how in the world I knew how to use those system
calls, the answer is simple: man pages. In <code>man 3p</code> there is thorough
documentation on every system call. If you know what you’re looking for, and
you just want to know how to use it, the man pages are your best friend. If you
don’t know what sort of interface the C library and Unix offer you, I would
point you toward the
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/">POSIX Specification</a>,
specifically Section 13, “Headers”. You can find each header and everything it
is required to define in there.</p>
<p>Obviously, this shell isn’t feature-rich. Some of its more glaring omissions
are:</p>
<ul>
 <li>Only whitespace separating arguments, no quoting or backslash escaping.</li>
 <li>No piping or redirection.</li>
 <li>Few standard builtins.</li>
 <li>No globbing.</li>
</ul>
<p>The implementation of all of this stuff is really interesting, but way more than
I could ever fit into an article like this. If I ever get around to
implementing any of them, I’ll be sure to write a follow-up about it. But I’d
encourage any reader to try implementing this stuff yourself. If you’re met
with success, drop me a line in the comments below, I’d love to see the code.</p>
<p>And finally, thanks for reading this tutorial (if anyone did). I enjoyed
writing it, and I hope you enjoyed reading it. Let me know what you think in
the comments!</p>
<p><strong>Edit:</strong> In an earlier version of this article, I had a couple nasty bugs in
<code>lsh_split_line()</code>, that just happened to cancel each other out. Thanks to
/u/munmap on Reddit (and other commenters) for catching them! Check
<a href="https://github.com/brenns10/lsh/commit/486ec6dcdd1e11c6dc82f482acda49ed18be11b5">this diff</a>
to see exactly what I did wrong.</p>
<p><strong>Edit 2:</strong> Thanks to user ghswa on GitHub for contributing some null checks for
 <code>malloc()</code> that I forgot. He/she also pointed out that the
 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html">manpage</a>
 for <code>getline()</code> specifies that the first argument should be freeable, so
 <code>line</code> should be initialized to <code>NULL</code> in my <code>lsh_read_line()</code> implementation
 that uses <code>getline()</code>.</p>
<p><strong>Edit 3:</strong> It’s 2020 and we’re still finding bugs, this is why software is
hard. Credit to <a href="https://github.com/harishankarv">harishankarv</a> on Github, for
finding an issue with my “simple” implementation of <code>lsh_read_line()</code> that
depends on <code>getline()</code>. See <a href="https://github.com/brenns10/lsh/issues/14">this issue</a>
for details – the text of the blog is updated.</p>
<h4>Footnotes</h4>
<hr />
 
 
 </div>||||I|||| * Stephen Brennan
 * Blog
 * Projects
 * Resume

 Tutorial - Write a Shell in C

 Stephen Brennan • 16 January 2015

 It’s easy to view yourself as “not a real programmer.” There are programs out there that everyone uses, and it’s easy to put their developers on a pedestal. Although developing large software projects isn’t easy, many times the basic idea of that software is quite simple. Implementing it yourself is a fun way to show that you have what it takes to be a real programmer. So, this is a walkthrough on how I wrote my own simplistic Unix shell in C, in the hopes that it makes other people feel that way too.

 The code for the shell described here, dubbed lsh, is available on GitHub.

 University students beware! Many classes have assignments that ask you to write a shell, and some faculty are aware of this tutorial and code. If you’re a student in such a class, you shouldn’t copy (or copy then modify) this code without permission. And even then, I would advise against heavily relying on this tutorial.

 Basic lifetime of a shell

 Let’s look at a shell from the top down. A shell does three main things in its lifetime.

 * Initialize: In this step, a typical shell would read and execute its configuration files. These change aspects of the shell’s behavior.
 * Interpret: Next, the shell reads commands from stdin (which could be interactive, or a file) and executes them.
 * Terminate: After its commands are executed, the shell executes any shutdown commands, frees up any memory, and terminates.

 These steps are so general that they could apply to many programs, but we’re going to use them for the basis for our shell. Our shell will be so simple that there won’t be any configuration files, and there won’t be any shutdown command. So, we’ll just call the looping function and then terminate. But in terms of architecture, it’s important to keep in mind that the lifetime of the program is more than just looping.

 int main(int argc, char **argv)
 {
 // Load config files, if any.
 
 // Run command loop.
 lsh_loop();
 
 // Perform any shutdown/cleanup.
 
 return EXIT_SUCCESS;
 }
 

 Here you can see that I just came up with a function, lsh_loop(), that will loop, interpreting commands. We’ll see the implementation of that next.

 Basic loop of a shell

 So we’ve taken care of how the program should start up. Now, for the basic program logic: what does the shell do during its loop? Well, a simple way to handle commands is with three steps:

 * Read: Read the command from standard input.
 * Parse: Separate the command string into a program and arguments.
 * Execute: Run the parsed command.

 Here, I’ll translate those ideas into code for lsh_loop():

 void lsh_loop(void)
 {
 char *line;
 char **args;
 int status;
 
 do {
 printf("> ");
 line = lsh_read_line();
 args = lsh_split_line(line);
 status = lsh_execute(args);
 
 free(line);
 free(args);
 } while (status);
 }
 

 Let’s walk through the code. The first few lines are just declarations. The do-while loop is more convenient for checking the status variable, because it executes once before checking its value. Within the loop, we print a prompt, call a function to read a line, call a function to split the line into args, and execute the args. Finally, we free the line and arguments that we created earlier. Note that we’re using a status variable returned by lsh_execute() to determine when to exit.

 Reading a line

 Reading a line from stdin sounds so simple, but in C it can be a hassle. The sad thing is that you don’t know ahead of time how much text a user will enter into their shell. You can’t simply allocate a block and hope they don’t exceed it. Instead, you need to start with a block, and if they do exceed it, reallocate with more space. This is a common strategy in C, and we’ll use it to implement lsh_read_line().

 #define LSH_RL_BUFSIZE 1024
 char *lsh_read_line(void)
 {
 int bufsize = LSH_RL_BUFSIZE;
 int position = 0;
 char *buffer = malloc(sizeof(char) * bufsize);
 int c;
 
 if (!buffer) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 
 while (1) {
 // Read a character
 c = getchar();
 
 // If we hit EOF, replace it with a null character and return.
 if (c == EOF || c == '\n') {
 buffer[position] = '\0';
 return buffer;
 } else {
 buffer[position] = c;
 }
 position++;
 
 // If we have exceeded the buffer, reallocate.
 if (position >= bufsize) {
 bufsize += LSH_RL_BUFSIZE;
 buffer = realloc(buffer, bufsize);
 if (!buffer) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 }
 }
 }
 

 The first part is a lot of declarations. If you hadn’t noticed, I prefer to keep the old C style of declaring variables before the rest of the code. The meat of the function is within the (apparently infinite) while (1) loop. In the loop, we read a character (and store it as an int, not a char, that’s important! EOF is an integer, not a character, and if you want to check for it, you need to use an int. This is a common beginner C mistake.). If it’s the newline, or EOF, we null terminate our current string and return it. Otherwise, we add the character to our existing string.

 Next, we see whether the next character will go outside of our current buffer size. If so, we reallocate our buffer (checking for allocation errors) before continuing. And that’s really it.

 Those who are intimately familiar with newer versions of the C library may note that there is a getline() function in stdio.h that does most of the work we just implemented. To be completely honest, I didn’t know it existed until after I wrote this code. This function was a GNU extension to the C library until 2008, when it was added to the specification, so most modern Unixes should have it now. I’m leaving my existing code the way it is, and I encourage people to learn it this way first before using getline. You’d be robbing yourself of a learning opportunity if you didn’t! Anyhow, with getline, the function becomes easier:

 char *lsh_read_line(void)
 {
 char *line = NULL;
 ssize_t bufsize = 0; // have getline allocate a buffer for us
 
 if (getline(&line, &bufsize, stdin) == -1){
 if (feof(stdin)) {
 exit(EXIT_SUCCESS); // We recieved an EOF
 } else {
 perror("readline");
 exit(EXIT_FAILURE);
 }
 }
 
 return line;
 }
 

 This is not 100% trivial because we still need to check for EOF or errors while reading. EOF (end of file) means that either we were reading commands from a text file which we’ve reached the end of, or the user typed Ctrl-D, which signals end-of-file. Either way, it means we should exit successfully, and if any other error occurs, we should fail after printing the error.

 Parsing the line

 OK, so if we look back at the loop, we see that we now have implemented lsh_read_line(), and we have the line of input. Now, we need to parse that line into a list of arguments. I’m going to make a glaring simplification here, and say that we won’t allow quoting or backslash escaping in our command line arguments. Instead, we will simply use whitespace to separate arguments from each other. So the command echo "this message" would not call echo with a single argument this message, but rather it would call echo with two arguments: "this and message".

 With those simplifications, all we need to do is “tokenize” the string using whitespace as delimiters. That means we can break out the classic library function strtok to do some of the dirty work for us.

 #define LSH_TOK_BUFSIZE 64
 #define LSH_TOK_DELIM " \t\r\n\a"
 char **lsh_split_line(char *line)
 {
 int bufsize = LSH_TOK_BUFSIZE, position = 0;
 char **tokens = malloc(bufsize * sizeof(char*));
 char *token;
 
 if (!tokens) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 
 token = strtok(line, LSH_TOK_DELIM);
 while (token != NULL) {
 tokens[position] = token;
 position++;
 
 if (position >= bufsize) {
 bufsize += LSH_TOK_BUFSIZE;
 tokens = realloc(tokens, bufsize * sizeof(char*));
 if (!tokens) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 }
 
 token = strtok(NULL, LSH_TOK_DELIM);
 }
 tokens[position] = NULL;
 return tokens;
 }
 

 If this code looks suspiciously similar to lsh_read_line(), it’s because it is! We are using the same strategy of having a buffer and dynamically expanding it. But this time, we’re doing it with a null-terminated array of pointers instead of a null-terminated array of characters.

 At the start of the function, we begin tokenizing by calling strtok. It returns a pointer to the first token. What strtok() actually does is return pointers to within the string you give it, and place \0 bytes at the end of each token. We store each pointer in an array (buffer) of character pointers.

 Finally, we reallocate the array of pointers if necessary. The process repeats until no token is returned by strtok, at which point we null-terminate the list of tokens.

 So, once all is said and done, we have an array of tokens, ready to execute. Which begs the question, how do we do that?

 How shells start processes

 Now, we’re really at the heart of what a shell does. Starting processes is the main function of shells. So writing a shell means that you need to know exactly what’s going on with processes and how they start. That’s why I’m going to take us on a short diversion to discuss processes in Unix-like operating systems.

 There are only two ways of starting processes on Unix. The first one (which almost doesn’t count) is by being Init. You see, when a Unix computer boots, its kernel is loaded. Once it is loaded and initialized, the kernel starts only one process, which is called Init. This process runs for the entire length of time that the computer is on, and it manages loading up the rest of the processes that you need for your computer to be useful.

 Since most programs aren’t Init, that leaves only one practical way for processes to get started: the fork() system call. When this function is called, the operating system makes a duplicate of the process and starts them both running. The original process is called the “parent”, and the new one is called the “child”. fork() returns 0 to the child process, and it returns to the parent the process ID number (PID) of its child. In essence, this means that the only way for new processes is to start is by an existing one duplicating itself.

 This might sound like a problem. Typically, when you want to run a new process, you don’t just want another copy of the same program – you want to run a different program. That’s what the exec() system call is all about. It replaces the current running program with an entirely new one. This means that when you call exec, the operating system stops your process, loads up the new program, and starts that one in its place. A process never returns from an exec() call (unless there’s an error).

 With these two system calls, we have the building blocks for how most programs are run on Unix. First, an existing process forks itself into two separate ones. Then, the child uses exec() to replace itself with a new program. The parent process can continue doing other things, and it can even keep tabs on its children, using the system call wait().

 Phew! That’s a lot of information, but with all that background, the following code for launching a program will actually make sense:

 int lsh_launch(char **args)
 {
 pid_t pid, wpid;
 int status;
 
 pid = fork();
 if (pid == 0) {
 // Child process
 if (execvp(args[0], args) == -1) {
 perror("lsh");
 }
 exit(EXIT_FAILURE);
 } else if (pid < 0) {
 // Error forking
 perror("lsh");
 } else {
 // Parent process
 do {
 wpid = waitpid(pid, &status, WUNTRACED);
 } while (!WIFEXITED(status) && !WIFSIGNALED(status));
 }
 
 return 1;
 }
 

 Alright. This function takes the list of arguments that we created earlier. Then, it forks the process, and saves the return value. Once fork() returns, we actually have two processes running concurrently. The child process will take the first if condition (where pid == 0).

 In the child process, we want to run the command given by the user. So, we use one of the many variants of the exec system call, execvp. The different variants of exec do slightly different things. Some take a variable number of string arguments. Others take a list of strings. Still others let you specify the environment that the process runs with. This particular variant expects a program name and an array (also called a vector, hence the ‘v’) of string arguments (the first one has to be the program name). The ‘p’ means that instead of providing the full file path of the program to run, we’re going to give its name, and let the operating system search for the program in the path.

 If the exec command returns -1 (or actually, if it returns at all), we know there was an error. So, we use perror to print the system’s error message, along with our program name, so users know where the error came from. Then, we exit so that the shell can keep running.

 The second condition (pid < 0) checks whether fork() had an error. If so, we print it and keep going – there’s no handling that error beyond telling the user and letting them decide if they need to quit.

 The third condition means that fork() executed successfully. The parent process will land here. We know that the child is going to execute the process, so the parent needs to wait for the command to finish running. We use waitpid() to wait for the process’s state to change. Unfortunately, waitpid() has a lot of options (like exec()). Processes can change state in lots of ways, and not all of them mean that the process has ended. A process can either exit (normally, or with an error code), or it can be killed by a signal. So, we use the macros provided with waitpid() to wait until either the processes are exited or killed. Then, the function finally returns a 1, as a signal to the calling function that we should prompt for input again.

 Shell Builtins

 You may have noticed that the lsh_loop() function calls lsh_execute(), but above, we titled our function lsh_launch(). This was intentional! You see, most commands a shell executes are programs, but not all of them. Some of them are built right into the shell.

 The reason is actually pretty simple. If you want to change directory, you need to use the function chdir(). The thing is, the current directory is a property of a process. So, if you wrote a program called cd that changed directory, it would just change its own current directory, and then terminate. Its parent process’s current directory would be unchanged. Instead, the shell process itself needs to execute chdir(), so that its own current directory is updated. Then, when it launches child processes, they will inherit that directory too.

 Similarly, if there was a program named exit, it wouldn’t be able to exit the shell that called it. That command also needs to be built into the shell. Also, most shells are configured by running configuration scripts, like ~/.bashrc. Those scripts use commands that change the operation of the shell. These commands could only change the shell’s operation if they were implemented within the shell process itself.

 So, it makes sense that we need to add some commands to the shell itself. The ones I added to my shell are cd, exit, and help. Here are their function implementations below:

 /*
 Function Declarations for builtin shell commands:
 */
 int lsh_cd(char **args);
 int lsh_help(char **args);
 int lsh_exit(char **args);
 
 /*
 List of builtin commands, followed by their corresponding functions.
 */
 char *builtin_str[] = {
 "cd",
 "help",
 "exit"
 };
 
 int (*builtin_func[]) (char **) = {
 &lsh_cd,
 &lsh_help,
 &lsh_exit
 };
 
 int lsh_num_builtins() {
 return sizeof(builtin_str) / sizeof(char *);
 }
 
 /*
 Builtin function implementations.
 */
 int lsh_cd(char **args)
 {
 if (args[1] == NULL) {
 fprintf(stderr, "lsh: expected argument to \"cd\"\n");
 } else {
 if (chdir(args[1]) != 0) {
 perror("lsh");
 }
 }
 return 1;
 }
 
 int lsh_help(char **args)
 {
 int i;
 printf("Stephen Brennan's LSH\n");
 printf("Type program names and arguments, and hit enter.\n");
 printf("The following are built in:\n");
 
 for (i = 0; i < lsh_num_builtins(); i++) {
 printf(" %s\n", builtin_str[i]);
 }
 
 printf("Use the man command for information on other programs.\n");
 return 1;
 }
 
 int lsh_exit(char **args)
 {
 return 0;
 }
 

 There are three parts to this code. The first part contains forward declarations of my functions. A forward declaration is when you declare (but don’t define) something, so that you can use its name before you define it. The reason I do this is because lsh_help() uses the array of builtins, and the arrays contain lsh_help(). The cleanest way to break this dependency cycle is by forward declaration.

 The next part is an array of builtin command names, followed by an array of their corresponding functions. This is so that, in the future, builtin commands can be added simply by modifying these arrays, rather than editing a large “switch” statement somewhere in the code. If you’re confused by the declaration of builtin_func, that’s OK! I am too. It’s an array of function pointers (that take array of strings and return an int). Any declaration involving function pointers in C can get really complicated. I still look up how function pointers are declared myself!1

 Finally, I implement each function. The lsh_cd() function first checks that its second argument exists, and prints an error message if it doesn’t. Then, it calls chdir(), checks for errors, and returns. The help function prints a nice message and the names of all the builtins. And the exit function returns 0, as a signal for the command loop to terminate.

 Putting together builtins and processes

 The last missing piece of the puzzle is to implement lsh_execute(), the function that will either launch a builtin, or a process. If you’re reading this far, you’ll know that we’ve set ourselves up for a really simple function:

 int lsh_execute(char **args)
 {
 int i;
 
 if (args[0] == NULL) {
 // An empty command was entered.
 return 1;
 }
 
 for (i = 0; i < lsh_num_builtins(); i++) {
 if (strcmp(args[0], builtin_str[i]) == 0) {
 return (*builtin_func[i])(args);
 }
 }
 
 return lsh_launch(args);
 }
 

 All this does is check if the command equals each builtin, and if so, run it. If it doesn’t match a builtin, it calls lsh_launch() to launch the process. The one caveat is that args might just contain NULL, if the user entered an empty string, or just whitespace. So, we need to check for that case at the beginning.

 Putting it all together

 That’s all the code that goes into the shell. If you’ve read along, you should understand completely how the shell works. To try it out (on a Linux machine), you would need to copy these code segments into a file (main.c), and compile it. Make sure to only include one implementation of lsh_read_line(). You’ll need to include the following headers at the top. I’ve added notes so that you know where each function comes from.

 * #include <sys/wait.h>
 + waitpid() and associated macros
 * #include <unistd.h>
 + chdir()
 + fork()
 + exec()
 + pid_t
 * #include <stdlib.h>
 + malloc()
 + realloc()
 + free()
 + exit()
 + execvp()
 + EXIT_SUCCESS, EXIT_FAILURE
 * #include <stdio.h>
 + fprintf()
 + printf()
 + stderr
 + getchar()
 + perror()
 * #include <string.h>
 + strcmp()
 + strtok()

 Once you have the code and headers, it should be as simple as running gcc -o main main.c to compile it, and then ./main to run it.

 Alternatively, you can get the code from GitHub. That link goes straight to the current revision of the code at the time of this writing– I may choose to update it and add new features someday in the future. If I do, I’ll try my best to update this article with the details and implementation ideas.

 Wrap up

 If you read this and wondered how in the world I knew how to use those system calls, the answer is simple: man pages. In man 3p there is thorough documentation on every system call. If you know what you’re looking for, and you just want to know how to use it, the man pages are your best friend. If you don’t know what sort of interface the C library and Unix offer you, I would point you toward the POSIX Specification, specifically Section 13, “Headers”. You can find each header and everything it is required to define in there.

 Obviously, this shell isn’t feature-rich. Some of its more glaring omissions are:

 * Only whitespace separating arguments, no quoting or backslash escaping.
 * No piping or redirection.
 * Few standard builtins.
 * No globbing.

 The implementation of all of this stuff is really interesting, but way more than I could ever fit into an article like this. If I ever get around to implementing any of them, I’ll be sure to write a follow-up about it. But I’d encourage any reader to try implementing this stuff yourself. If you’re met with success, drop me a line in the comments below, I’d love to see the code.

 And finally, thanks for reading this tutorial (if anyone did). I enjoyed writing it, and I hope you enjoyed reading it. Let me know what you think in the comments!

 Edit: In an earlier version of this article, I had a couple nasty bugs in lsh_split_line(), that just happened to cancel each other out. Thanks to /u/munmap on Reddit (and other commenters) for catching them! Check this diff to see exactly what I did wrong.

 Edit 2: Thanks to user ghswa on GitHub for contributing some null checks for malloc() that I forgot. He/she also pointed out that the manpage for getline() specifies that the first argument should be freeable, so line should be initialized to NULL in my lsh_read_line() implementation that uses getline().

 Edit 3: It’s 2020 and we’re still finding bugs, this is why software is hard. Credit to harishankarv on Github, for finding an issue with my “simple” implementation of lsh_read_line() that depends on getline(). See this issue for details – the text of the blog is updated.

 Footnotes

 1. Edit 4/Footnote: It’s 2021, over 6.5 years since writing this tutorial. I now work on operating systems in C for a living. I just wanted to say that I still do not remember how to declare a function pointer. I still need to Google it every time. ↩

 * Share on:
 * 
 * 
 * 
 * 
 Legal • RSS



 Stephen Brennan's Blog is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License
Stephen Brennan • 16 January 2015  It’s easy to view yourself as “not a real programmer.” There are programs out
there that everyone uses, and it’s easy to put their developers on a pedestal.
Although developing large software projects isn’t easy, many times the basic
idea of that software is quite simple. Implementing it yourself is a fun way to
show that you have what it takes to be a real programmer. So, this is a
walkthrough on how I wrote my own simplistic Unix shell in C, in the hopes that
it makes other people feel that way too.
The code for the shell described here, dubbed lsh, is available on
GitHub.
 University students beware! Many classes have assignments that ask you to
write a shell, and some faculty are aware of this tutorial and code. If you’re
a student in such a class, you shouldn’t copy (or copy then modify) this code
without permission. And even then, I would advise against heavily relying on this tutorial.
Basic lifetime of a shell
Let’s look at a shell from the top down. A shell does three main things in its
lifetime.
  Initialize: In this step, a typical shell would read and execute its
configuration files. These change aspects of the shell’s behavior.
  Interpret: Next, the shell reads commands from stdin (which could be
interactive, or a file) and executes them.
  Terminate: After its commands are executed, the shell executes any
shutdown commands, frees up any memory, and terminates.
These steps are so general that they could apply to many programs, but we’re
going to use them for the basis for our shell. Our shell will be so simple that
there won’t be any configuration files, and there won’t be any shutdown command.
So, we’ll just call the looping function and then terminate. But in terms of
architecture, it’s important to keep in mind that the lifetime of the program is
more than just looping.
  int main(int argc, char **argv)
{
 // Load config files, if any.
 // Run command loop.
 lsh_loop();
 // Perform any shutdown/cleanup.
 return EXIT_SUCCESS;
}
  
Here you can see that I just came up with a function, lsh_loop(), that will
loop, interpreting commands. We’ll see the implementation of that next.
Basic loop of a shell
So we’ve taken care of how the program should start up. Now, for the basic
program logic: what does the shell do during its loop? Well, a simple way to
handle commands is with three steps:
  Read: Read the command from standard input.
  Parse: Separate the command string into a program and arguments.
  Execute: Run the parsed command.
Here, I’ll translate those ideas into code for lsh_loop():
  void lsh_loop(void)
{
 char *line;
 char **args;
 int status;
 do {
 printf("&gt; ");
 line = lsh_read_line();
 args = lsh_split_line(line);
 status = lsh_execute(args);
 free(line);
 free(args);
 } while (status);
}
  
Let’s walk through the code. The first few lines are just declarations. The
do-while loop is more convenient for checking the status variable, because it
executes once before checking its value. Within the loop, we print a prompt,
call a function to read a line, call a function to split the line into args, and
execute the args. Finally, we free the line and arguments that we created
earlier. Note that we’re using a status variable returned by lsh_execute() to
determine when to exit.
Reading a line
Reading a line from stdin sounds so simple, but in C it can be a hassle. The
sad thing is that you don’t know ahead of time how much text a user will enter
into their shell. You can’t simply allocate a block and hope they don’t exceed
it. Instead, you need to start with a block, and if they do exceed it,
reallocate with more space. This is a common strategy in C, and we’ll use it to
implement lsh_read_line().
  #define LSH_RL_BUFSIZE 1024
char *lsh_read_line(void)
{
 int bufsize = LSH_RL_BUFSIZE;
 int position = 0;
 char *buffer = malloc(sizeof(char) * bufsize);
 int c;
 if (!buffer) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 while (1) {
 // Read a character
 c = getchar();
 // If we hit EOF, replace it with a null character and return.
 if (c == EOF || c == '\n') {
 buffer[position] = '\0';
 return buffer;
 } else {
 buffer[position] = c;
 }
 position++;
 // If we have exceeded the buffer, reallocate.
 if (position &gt;= bufsize) {
 bufsize += LSH_RL_BUFSIZE;
 buffer = realloc(buffer, bufsize);
 if (!buffer) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 }
 }
}
  
The first part is a lot of declarations. If you hadn’t noticed, I prefer to
keep the old C style of declaring variables before the rest of the code. The
meat of the function is within the (apparently infinite) while (1) loop. In
the loop, we read a character (and store it as an int, not a char, that’s
important! EOF is an integer, not a character, and if you want to check for it,
you need to use an int. This is a common beginner C mistake.). If it’s the
newline, or EOF, we null terminate our current string and return it. Otherwise,
we add the character to our existing string.
Next, we see whether the next character will go outside of our current buffer
size. If so, we reallocate our buffer (checking for allocation errors) before
continuing. And that’s really it.
Those who are intimately familiar with newer versions of the C library may note
that there is a getline() function in stdio.h that does most of the work we
just implemented. To be completely honest, I didn’t know it existed until after
I wrote this code. This function was a GNU extension to the C library until
2008, when it was added to the specification, so most modern Unixes should have
it now. I’m leaving my existing code the way it is, and I encourage people to
learn it this way first before using getline. You’d be robbing yourself of a
learning opportunity if you didn’t! Anyhow, with getline, the function
becomes easier:
  char *lsh_read_line(void)
{
 char *line = NULL;
 ssize_t bufsize = 0; // have getline allocate a buffer for us
 if (getline(&amp;line, &amp;bufsize, stdin) == -1){
 if (feof(stdin)) {
 exit(EXIT_SUCCESS); // We recieved an EOF
 } else {
 perror("readline");
 exit(EXIT_FAILURE);
 }
 }
 return line;
}
  
This is not 100% trivial because we still need to check for EOF or errors while
reading. EOF (end of file) means that either we were reading commands from a
text file which we’ve reached the end of, or the user typed Ctrl-D, which
signals end-of-file. Either way, it means we should exit successfully, and if
any other error occurs, we should fail after printing the error.
Parsing the line
OK, so if we look back at the loop, we see that we now have implemented
lsh_read_line(), and we have the line of input. Now, we need to parse that
line into a list of arguments. I’m going to make a glaring simplification here,
and say that we won’t allow quoting or backslash escaping in our command line
arguments. Instead, we will simply use whitespace to separate arguments from
each other. So the command echo "this message" would not call echo with a
single argument this message, but rather it would call echo with two
arguments: "this and message".
With those simplifications, all we need to do is “tokenize” the string using
whitespace as delimiters. That means we can break out the classic library
function strtok to do some of the dirty work for us.
  #define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
char **lsh_split_line(char *line)
{
 int bufsize = LSH_TOK_BUFSIZE, position = 0;
 char **tokens = malloc(bufsize * sizeof(char*));
 char *token;
 if (!tokens) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 token = strtok(line, LSH_TOK_DELIM);
 while (token != NULL) {
 tokens[position] = token;
 position++;
 if (position &gt;= bufsize) {
 bufsize += LSH_TOK_BUFSIZE;
 tokens = realloc(tokens, bufsize * sizeof(char*));
 if (!tokens) {
 fprintf(stderr, "lsh: allocation error\n");
 exit(EXIT_FAILURE);
 }
 }
 token = strtok(NULL, LSH_TOK_DELIM);
 }
 tokens[position] = NULL;
 return tokens;
}
  
If this code looks suspiciously similar to lsh_read_line(), it’s because it
is! We are using the same strategy of having a buffer and dynamically expanding
it. But this time, we’re doing it with a null-terminated array of pointers
instead of a null-terminated array of characters.
At the start of the function, we begin tokenizing by calling strtok. It
returns a pointer to the first token. What strtok() actually does is return
pointers to within the string you give it, and place \0 bytes at the end of
each token. We store each pointer in an array (buffer) of character
pointers.
Finally, we reallocate the array of pointers if necessary. The process repeats
until no token is returned by strtok, at which point we null-terminate the
list of tokens.
So, once all is said and done, we have an array of tokens, ready to execute.
Which begs the question, how do we do that?
How shells start processes
Now, we’re really at the heart of what a shell does. Starting processes is the
main function of shells. So writing a shell means that you need to know exactly
what’s going on with processes and how they start. That’s why I’m going to take
us on a short diversion to discuss processes in Unix-like operating systems.
There are only two ways of starting processes on Unix. The first one (which
almost doesn’t count) is by being Init. You see, when a Unix computer boots,
its kernel is loaded. Once it is loaded and initialized, the kernel starts only
one process, which is called Init. This process runs for the entire length of
time that the computer is on, and it manages loading up the rest of the
processes that you need for your computer to be useful.
Since most programs aren’t Init, that leaves only one practical way for
processes to get started: the fork() system call. When this function is
called, the operating system makes a duplicate of the process and starts them
both running. The original process is called the “parent”, and the new one is
called the “child”. fork() returns 0 to the child process, and it returns to
the parent the process ID number (PID) of its child. In essence, this means
that the only way for new processes is to start is by an existing one
duplicating itself.
This might sound like a problem. Typically, when you want to run a new process,
you don’t just want another copy of the same program – you want to run a
different program. That’s what the exec() system call is all about. It
replaces the current running program with an entirely new one. This means that
when you call exec, the operating system stops your process, loads up the new
program, and starts that one in its place. A process never returns from an
exec() call (unless there’s an error).
With these two system calls, we have the building blocks for how most programs
are run on Unix. First, an existing process forks itself into two separate
ones. Then, the child uses exec() to replace itself with a new program. The
parent process can continue doing other things, and it can even keep tabs on its
children, using the system call wait().
Phew! That’s a lot of information, but with all that background, the following
code for launching a program will actually make sense:
  int lsh_launch(char **args)
{
 pid_t pid, wpid;
 int status;
 pid = fork();
 if (pid == 0) {
 // Child process
 if (execvp(args[0], args) == -1) {
 perror("lsh");
 }
 exit(EXIT_FAILURE);
 } else if (pid &lt; 0) {
 // Error forking
 perror("lsh");
 } else {
 // Parent process
 do {
 wpid = waitpid(pid, &amp;status, WUNTRACED);
 } while (!WIFEXITED(status) &amp;&amp; !WIFSIGNALED(status));
 }
 return 1;
}
  
Alright. This function takes the list of arguments that we created earlier.
Then, it forks the process, and saves the return value. Once fork() returns,
we actually have two processes running concurrently. The child process will
take the first if condition (where pid == 0).
In the child process, we want to run the command given by the user. So, we use
one of the many variants of the exec system call, execvp. The different
variants of exec do slightly different things. Some take a variable number of
string arguments. Others take a list of strings. Still others let you specify
the environment that the process runs with. This particular variant expects a
program name and an array (also called a vector, hence the ‘v’) of string
arguments (the first one has to be the program name). The ‘p’ means that
instead of providing the full file path of the program to run, we’re going to
give its name, and let the operating system search for the program in the path.
If the exec command returns -1 (or actually, if it returns at all), we know
there was an error. So, we use perror to print the system’s error message,
along with our program name, so users know where the error came from. Then, we
exit so that the shell can keep running.
The second condition (pid &lt; 0) checks whether fork() had an error. If so,
we print it and keep going – there’s no handling that error beyond telling the
user and letting them decide if they need to quit.
The third condition means that fork() executed successfully. The parent
process will land here. We know that the child is going to execute the process,
so the parent needs to wait for the command to finish running. We use
waitpid() to wait for the process’s state to change. Unfortunately,
waitpid() has a lot of options (like exec()). Processes can change state in
lots of ways, and not all of them mean that the process has ended. A process
can either exit (normally, or with an error code), or it can be killed by a
signal. So, we use the macros provided with waitpid() to wait until either
the processes are exited or killed. Then, the function finally returns a 1, as
a signal to the calling function that we should prompt for input again.
Shell Builtins
You may have noticed that the lsh_loop() function calls lsh_execute(), but
above, we titled our function lsh_launch(). This was intentional! You see,
most commands a shell executes are programs, but not all of them. Some of them
are built right into the shell.
The reason is actually pretty simple. If you want to change directory, you need
to use the function chdir(). The thing is, the current directory is a
property of a process. So, if you wrote a program called cd that changed
directory, it would just change its own current directory, and then terminate.
Its parent process’s current directory would be unchanged. Instead, the shell
process itself needs to execute chdir(), so that its own current directory is
updated. Then, when it launches child processes, they will inherit that
directory too.
Similarly, if there was a program named exit, it wouldn’t be able to exit the
shell that called it. That command also needs to be built into the shell.
Also, most shells are configured by running configuration scripts, like
~/.bashrc. Those scripts use commands that change the operation of the shell.
These commands could only change the shell’s operation if they were implemented
within the shell process itself.
So, it makes sense that we need to add some commands to the shell itself. The
ones I added to my shell are cd, exit, and help. Here are their function
implementations below:
  /*
 Function Declarations for builtin shell commands:
 */
int lsh_cd(char **args);
int lsh_help(char **args);
int lsh_exit(char **args);
/*
 List of builtin commands, followed by their corresponding functions.
 */
char *builtin_str[] = {
 "cd",
 "help",
 "exit"
};
int (*builtin_func[]) (char **) = {
 &amp;lsh_cd,
 &amp;lsh_help,
 &amp;lsh_exit
};
int lsh_num_builtins() {
 return sizeof(builtin_str) / sizeof(char *);
}
/*
 Builtin function implementations.
*/
int lsh_cd(char **args)
{
 if (args[1] == NULL) {
 fprintf(stderr, "lsh: expected argument to \"cd\"\n");
 } else {
 if (chdir(args[1]) != 0) {
 perror("lsh");
 }
 }
 return 1;
}
int lsh_help(char **args)
{
 int i;
 printf("Stephen Brennan's LSH\n");
 printf("Type program names and arguments, and hit enter.\n");
 printf("The following are built in:\n");
 for (i = 0; i &lt; lsh_num_builtins(); i++) {
 printf(" %s\n", builtin_str[i]);
 }
 printf("Use the man command for information on other programs.\n");
 return 1;
}
int lsh_exit(char **args)
{
 return 0;
}
  
There are three parts to this code. The first part contains forward
declarations of my functions. A forward declaration is when you declare (but
don’t define) something, so that you can use its name before you define it. The
reason I do this is because lsh_help() uses the array of builtins, and the
arrays contain lsh_help(). The cleanest way to break this dependency cycle is
by forward declaration.
The next part is an array of builtin command names, followed by an array of
their corresponding functions. This is so that, in the future, builtin commands
can be added simply by modifying these arrays, rather than editing a large
“switch” statement somewhere in the code. If you’re confused by the declaration
of builtin_func, that’s OK! I am too. It’s an array of function pointers
(that take array of strings and return an int). Any declaration involving
function pointers in C can get really complicated. I still look up how function
pointers are declared myself! 1  
Finally, I implement each function. The lsh_cd() function first checks that
its second argument exists, and prints an error message if it doesn’t. Then, it
calls chdir(), checks for errors, and returns. The help function prints a
nice message and the names of all the builtins. And the exit function returns
0, as a signal for the command loop to terminate.
Putting together builtins and processes
The last missing piece of the puzzle is to implement lsh_execute(), the
function that will either launch a builtin, or a process. If you’re reading
this far, you’ll know that we’ve set ourselves up for a really simple function:
  int lsh_execute(char **args)
{
 int i;
 if (args[0] == NULL) {
 // An empty command was entered.
 return 1;
 }
 for (i = 0; i &lt; lsh_num_builtins(); i++) {
 if (strcmp(args[0], builtin_str[i]) == 0) {
 return (*builtin_func[i])(args);
 }
 }
 return lsh_launch(args);
}
  
All this does is check if the command equals each builtin, and if so, run it.
If it doesn’t match a builtin, it calls lsh_launch() to launch the process.
The one caveat is that args might just contain NULL, if the user entered an
empty string, or just whitespace. So, we need to check for that case at the
beginning.
Putting it all together
That’s all the code that goes into the shell. If you’ve read along, you should
understand completely how the shell works. To try it out (on a Linux machine),
you would need to copy these code segments into a file (main.c), and compile
it. Make sure to only include one implementation of lsh_read_line(). You’ll
need to include the following headers at the top. I’ve added notes so that you
know where each function comes from.
  #include &lt;sys/wait.h&gt;
 
  waitpid() and associated macros
 
 
  #include &lt;unistd.h&gt;
 
  chdir() 
  fork() 
  exec() 
  pid_t 
 
 
  #include &lt;stdlib.h&gt;
 
  malloc() 
  realloc() 
  free() 
  exit() 
  execvp() 
  EXIT_SUCCESS, EXIT_FAILURE 
 
 
  #include &lt;stdio.h&gt;
 
  fprintf() 
  printf() 
  stderr 
  getchar() 
  perror() 
 
 
  #include &lt;string.h&gt;
 
  strcmp() 
  strtok() 
 
 
Once you have the code and headers, it should be as simple as running gcc -o
main main.c to compile it, and then ./main to run it.
Alternatively, you can get the code from
GitHub.
That link goes straight to the current revision of the code at the time of this
writing– I may choose to update it and add new features someday in the future.
If I do, I’ll try my best to update this article with the details and
implementation ideas.
Wrap up
If you read this and wondered how in the world I knew how to use those system
calls, the answer is simple: man pages. In man 3p there is thorough
documentation on every system call. If you know what you’re looking for, and
you just want to know how to use it, the man pages are your best friend. If you
don’t know what sort of interface the C library and Unix offer you, I would
point you toward the
POSIX Specification,
specifically Section 13, “Headers”. You can find each header and everything it
is required to define in there.
Obviously, this shell isn’t feature-rich. Some of its more glaring omissions
are:
 Only whitespace separating arguments, no quoting or backslash escaping.
 No piping or redirection.
 Few standard builtins.
 No globbing.
The implementation of all of this stuff is really interesting, but way more than
I could ever fit into an article like this. If I ever get around to
implementing any of them, I’ll be sure to write a follow-up about it. But I’d
encourage any reader to try implementing this stuff yourself. If you’re met
with success, drop me a line in the comments below, I’d love to see the code.
And finally, thanks for reading this tutorial (if anyone did). I enjoyed
writing it, and I hope you enjoyed reading it. Let me know what you think in
the comments!
 Edit: In an earlier version of this article, I had a couple nasty bugs in
lsh_split_line(), that just happened to cancel each other out. Thanks to
/u/munmap on Reddit (and other commenters) for catching them! Check
this diff
to see exactly what I did wrong.
 Edit 2: Thanks to user ghswa on GitHub for contributing some null checks for
 malloc() that I forgot. He/she also pointed out that the
 manpage
 for getline() specifies that the first argument should be freeable, so
 line should be initialized to NULL in my lsh_read_line() implementation
 that uses getline().
 Edit 3: It’s 2020 and we’re still finding bugs, this is why software is
hard. Credit to harishankarv on Github, for
finding an issue with my “simple” implementation of lsh_read_line() that
depends on getline(). See this issue
for details – the text of the blog is updated.
Footnotes
Tutorial - Write a Shell in C - Stephen Brennan
https://brennan.io/2015/01/16/write-a-shell-in-c/
https://www.geeksforgeeks.org/making-linux-shell-c/
Making your own Linux Shell in C - GeeksforGeeks
2017-08-29
GeeksforGeeks
<div><div><p><code>#include&lt;stdio.h&gt;</code></p><p><code>#include&lt;string.h&gt;</code></p><p><code>#include&lt;stdlib.h&gt;</code></p><p><code>#include&lt;unistd.h&gt;</code></p><p><code>#include&lt;sys/types.h&gt;</code></p><p><code>#include&lt;sys/wait.h&gt;</code></p><p><code>#include&lt;readline/readline.h&gt;</code></p><p><code>#include&lt;readline/history.h&gt;</code></p><p><code>#define MAXCOM 1000 // max number of letters to be supported</code></p><p><code>#define MAXLIST 100 // max number of commands to be supported</code></p><p><code>#define clear() printf("\033[H\033[J")</code></p><p><code>void</code> <code>init_shell()</code></p><p><code>{</code></p><p><code>    </code><code>clear();</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\n\n\n\n******************"</code></p><p><code>        </code><code>"************************"</code><code>);</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\n\n\n\t****MY SHELL****"</code><code>);</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\n\n\t-USE AT YOUR OWN RISK-"</code><code>);</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\n\n\n\n*******************"</code></p><p><code>        </code><code>"***********************"</code><code>);</code></p><p><code>    </code><code>char</code><code>* username = </code><code>getenv</code><code>(</code><code>"USER"</code><code>);</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\n\n\nUSER is: @%s"</code><code>, username);</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\n"</code><code>);</code></p><p><code>    </code><code>sleep(1);</code></p><p><code>    </code><code>clear();</code></p><p><code>}</code></p><p><code>int</code> <code>takeInput(</code><code>char</code><code>* str)</code></p><p><code>{</code></p><p><code>    </code><code>char</code><code>* buf;</code></p><p><code>    </code><code>buf = readline(</code><code>"\n&gt;&gt;&gt; "</code><code>);</code></p><p><code>    </code><code>if</code> <code>(</code><code>strlen</code><code>(buf) != 0) {</code></p><p><code>        </code><code>add_history(buf);</code></p><p><code>        </code><code>strcpy</code><code>(str, buf);</code></p><p><code>        </code><code>return</code> <code>0;</code></p><p><code>    </code><code>} </code><code>else</code> <code>{</code></p><p><code>        </code><code>return</code> <code>1;</code></p><p><code>    </code><code>}</code></p><p><code>}</code></p><p><code>void</code> <code>printDir()</code></p><p><code>{</code></p><p><code>    </code><code>char</code> <code>cwd[1024];</code></p><p><code>    </code><code>getcwd(cwd, </code><code>sizeof</code><code>(cwd));</code></p><p><code>    </code><code>printf</code><code>(</code><code>"\nDir: %s"</code><code>, cwd);</code></p><p><code>}</code></p><p><code>void</code> <code>execArgs(</code><code>char</code><code>** parsed)</code></p><p><code>{</code></p><p><code>    </code><code>pid_t pid = fork(); </code></p><p><code>    </code><code>if</code> <code>(pid == -1) {</code></p><p><code>        </code><code>printf</code><code>(</code><code>"\nFailed forking child.."</code><code>);</code></p><p><code>        </code><code>return</code><code>;</code></p><p><code>    </code><code>} </code><code>else</code> <code>if</code> <code>(pid == 0) {</code></p><p><code>        </code><code>if</code> <code>(execvp(parsed[0], parsed) &lt; 0) {</code></p><p><code>            </code><code>printf</code><code>(</code><code>"\nCould not execute command.."</code><code>);</code></p><p><code>        </code><code>}</code></p><p><code>        </code><code>exit</code><code>(0);</code></p><p><code>    </code><code>} </code><code>else</code> <code>{</code></p><p><code>        </code><code>wait(NULL); </code></p><p><code>        </code><code>return</code><code>;</code></p><p><code>    </code><code>}</code></p><p><code>}</code></p><p><code>void</code> <code>execArgsPiped(</code><code>char</code><code>** parsed, </code><code>char</code><code>** parsedpipe)</code></p><p><code>{</code></p><p><code>    </code><code>int</code> <code>pipefd[2]; </code></p><p><code>    </code><code>pid_t p1, p2;</code></p><p><code>    </code><code>if</code> <code>(pipe(pipefd) &lt; 0) {</code></p><p><code>        </code><code>printf</code><code>(</code><code>"\nPipe could not be initialized"</code><code>);</code></p><p><code>        </code><code>return</code><code>;</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>p1 = fork();</code></p><p><code>    </code><code>if</code> <code>(p1 &lt; 0) {</code></p><p><code>        </code><code>printf</code><code>(</code><code>"\nCould not fork"</code><code>);</code></p><p><code>        </code><code>return</code><code>;</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>if</code> <code>(p1 == 0) {</code></p><p><code>        </code><code>close(pipefd[0]);</code></p><p><code>        </code><code>dup2(pipefd[1], STDOUT_FILENO);</code></p><p><code>        </code><code>close(pipefd[1]);</code></p><p><code>        </code><code>if</code> <code>(execvp(parsed[0], parsed) &lt; 0) {</code></p><p><code>            </code><code>printf</code><code>(</code><code>"\nCould not execute command 1.."</code><code>);</code></p><p><code>            </code><code>exit</code><code>(0);</code></p><p><code>        </code><code>}</code></p><p><code>    </code><code>} </code><code>else</code> <code>{</code></p><p><code>        </code><code>p2 = fork();</code></p><p><code>        </code><code>if</code> <code>(p2 &lt; 0) {</code></p><p><code>            </code><code>printf</code><code>(</code><code>"\nCould not fork"</code><code>);</code></p><p><code>            </code><code>return</code><code>;</code></p><p><code>        </code><code>}</code></p><p><code>        </code><code>if</code> <code>(p2 == 0) {</code></p><p><code>            </code><code>close(pipefd[1]);</code></p><p><code>            </code><code>dup2(pipefd[0], STDIN_FILENO);</code></p><p><code>            </code><code>close(pipefd[0]);</code></p><p><code>            </code><code>if</code> <code>(execvp(parsedpipe[0], parsedpipe) &lt; 0) {</code></p><p><code>                </code><code>printf</code><code>(</code><code>"\nCould not execute command 2.."</code><code>);</code></p><p><code>                </code><code>exit</code><code>(0);</code></p><p><code>            </code><code>}</code></p><p><code>        </code><code>} </code><code>else</code> <code>{</code></p><p><code>            </code><code>wait(NULL);</code></p><p><code>            </code><code>wait(NULL);</code></p><p><code>        </code><code>}</code></p><p><code>    </code><code>}</code></p><p><code>}</code></p><p><code>void</code> <code>openHelp()</code></p><p><code>{</code></p><p><code>    </code><code>puts</code><code>(</code><code>"\n***WELCOME TO MY SHELL HELP***"</code></p><p><code>        </code><code>"\nCopyright @ Suprotik Dey"</code></p><p><code>        </code><code>"\n-Use the shell at your own risk..."</code></p><p><code>        </code><code>"\nList of Commands supported:"</code></p><p><code>        </code><code>"\n&gt;cd"</code></p><p><code>        </code><code>"\n&gt;ls"</code></p><p><code>        </code><code>"\n&gt;exit"</code></p><p><code>        </code><code>"\n&gt;all other general commands available in UNIX shell"</code></p><p><code>        </code><code>"\n&gt;pipe handling"</code></p><p><code>        </code><code>"\n&gt;improper space handling"</code><code>);</code></p><p><code>    </code><code>return</code><code>;</code></p><p><code>}</code></p><p><code>int</code> <code>ownCmdHandler(</code><code>char</code><code>** parsed)</code></p><p><code>{</code></p><p><code>    </code><code>int</code> <code>NoOfOwnCmds = 4, i, switchOwnArg = 0;</code></p><p><code>    </code><code>char</code><code>* ListOfOwnCmds[NoOfOwnCmds];</code></p><p><code>    </code><code>char</code><code>* username;</code></p><p><code>    </code><code>ListOfOwnCmds[0] = </code><code>"exit"</code><code>;</code></p><p><code>    </code><code>ListOfOwnCmds[1] = </code><code>"cd"</code><code>;</code></p><p><code>    </code><code>ListOfOwnCmds[2] = </code><code>"help"</code><code>;</code></p><p><code>    </code><code>ListOfOwnCmds[3] = </code><code>"hello"</code><code>;</code></p><p><code>    </code><code>for</code> <code>(i = 0; i &lt; NoOfOwnCmds; i++) {</code></p><p><code>        </code><code>if</code> <code>(</code><code>strcmp</code><code>(parsed[0], ListOfOwnCmds[i]) == 0) {</code></p><p><code>            </code><code>switchOwnArg = i + 1;</code></p><p><code>            </code><code>break</code><code>;</code></p><p><code>        </code><code>}</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>switch</code> <code>(switchOwnArg) {</code></p><p><code>    </code><code>case</code> <code>1:</code></p><p><code>        </code><code>printf</code><code>(</code><code>"\nGoodbye\n"</code><code>);</code></p><p><code>        </code><code>exit</code><code>(0);</code></p><p><code>    </code><code>case</code> <code>2:</code></p><p><code>        </code><code>chdir(parsed[1]);</code></p><p><code>        </code><code>return</code> <code>1;</code></p><p><code>    </code><code>case</code> <code>3:</code></p><p><code>        </code><code>openHelp();</code></p><p><code>        </code><code>return</code> <code>1;</code></p><p><code>    </code><code>case</code> <code>4:</code></p><p><code>        </code><code>username = </code><code>getenv</code><code>(</code><code>"USER"</code><code>);</code></p><p><code>        </code><code>printf</code><code>(</code><code>"\nHello %s.\nMind that this is "</code></p><p><code>            </code><code>"not a place to play around."</code></p><p><code>            </code><code>"\nUse help to know more..\n"</code><code>,</code></p><p><code>            </code><code>username);</code></p><p><code>        </code><code>return</code> <code>1;</code></p><p><code>    </code><code>default</code><code>:</code></p><p><code>        </code><code>break</code><code>;</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>return</code> <code>0;</code></p><p><code>}</code></p><p><code>int</code> <code>parsePipe(</code><code>char</code><code>* str, </code><code>char</code><code>** strpiped)</code></p><p><code>{</code></p><p><code>    </code><code>int</code> <code>i;</code></p><p><code>    </code><code>for</code> <code>(i = 0; i &lt; 2; i++) {</code></p><p><code>        </code><code>strpiped[i] = strsep(&amp;str, </code><code>"|"</code><code>);</code></p><p><code>        </code><code>if</code> <code>(strpiped[i] == NULL)</code></p><p><code>            </code><code>break</code><code>;</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>if</code> <code>(strpiped[1] == NULL)</code></p><p><code>        </code><code>return</code> <code>0; </code></p><p><code>    </code><code>else</code> <code>{</code></p><p><code>        </code><code>return</code> <code>1;</code></p><p><code>    </code><code>}</code></p><p><code>}</code></p><p><code>void</code> <code>parseSpace(</code><code>char</code><code>* str, </code><code>char</code><code>** parsed)</code></p><p><code>{</code></p><p><code>    </code><code>int</code> <code>i;</code></p><p><code>    </code><code>for</code> <code>(i = 0; i &lt; MAXLIST; i++) {</code></p><p><code>        </code><code>parsed[i] = strsep(&amp;str, </code><code>" "</code><code>);</code></p><p><code>        </code><code>if</code> <code>(parsed[i] == NULL)</code></p><p><code>            </code><code>break</code><code>;</code></p><p><code>        </code><code>if</code> <code>(</code><code>strlen</code><code>(parsed[i]) == 0)</code></p><p><code>            </code><code>i--;</code></p><p><code>    </code><code>}</code></p><p><code>}</code></p><p><code>int</code> <code>processString(</code><code>char</code><code>* str, </code><code>char</code><code>** parsed, </code><code>char</code><code>** parsedpipe)</code></p><p><code>{</code></p><p><code>    </code><code>char</code><code>* strpiped[2];</code></p><p><code>    </code><code>int</code> <code>piped = 0;</code></p><p><code>    </code><code>piped = parsePipe(str, strpiped);</code></p><p><code>    </code><code>if</code> <code>(piped) {</code></p><p><code>        </code><code>parseSpace(strpiped[0], parsed);</code></p><p><code>        </code><code>parseSpace(strpiped[1], parsedpipe);</code></p><p><code>    </code><code>} </code><code>else</code> <code>{</code></p><p><code>        </code><code>parseSpace(str, parsed);</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>if</code> <code>(ownCmdHandler(parsed))</code></p><p><code>        </code><code>return</code> <code>0;</code></p><p><code>    </code><code>else</code></p><p><code>        </code><code>return</code> <code>1 + piped;</code></p><p><code>}</code></p><p><code>int</code> <code>main()</code></p><p><code>{</code></p><p><code>    </code><code>char</code> <code>inputString[MAXCOM], *parsedArgs[MAXLIST];</code></p><p><code>    </code><code>char</code><code>* parsedArgsPiped[MAXLIST];</code></p><p><code>    </code><code>int</code> <code>execFlag = 0;</code></p><p><code>    </code><code>init_shell();</code></p><p><code>    </code><code>while</code> <code>(1) {</code></p><p><code>        </code><code>printDir();</code></p><p><code>        </code><code>if</code> <code>(takeInput(inputString))</code></p><p><code>            </code><code>continue</code><code>;</code></p><p><code>        </code><code>execFlag = processString(inputString,</code></p><p><code>        </code><code>parsedArgs, parsedArgsPiped);</code></p><p><code>        </code><code>if</code> <code>(execFlag == 1)</code></p><p><code>            </code><code>execArgs(parsedArgs);</code></p><p><code>        </code><code>if</code> <code>(execFlag == 2)</code></p><p><code>            </code><code>execArgsPiped(parsedArgs, parsedArgsPiped);</code></p><p><code>    </code><code>}</code></p><p><code>    </code><code>return</code> <code>0;</code></p><p><code>}</code></p></div>||||I|||| Skip to content
 * Courses
 + For Working Professionals
 o DevOps(Live)
 o Data Structure & Algorithm Classes (Live)
 o System Design (Live)
 o Java Backend Developer (Live)
 o Full Stack Development with React & Node JS (Live)
 o Complete Data Science Program
 o Data Structure & Algorithm-Self Paced(C++/JAVA)
 o Data Structures & Algorithms in Python
 o Explore More Live Courses
 + For Students
 o Competitive Programming (Live)
 o Interview Preparation Course
 o Data Structure & Algorithm-Self Paced(C++/JAVA)
 o Data Structures & Algorithms in Python
 o Data Science (Live)
 o Full Stack Development with React & Node JS (Live)
 o GATE CS 2023 Test Series
 o OS DBMS CN for SDE Interview Preparation
 o Explore More Self-Paced Courses
 + Programming Languages
 o C++ Programming - Beginner to Advanced
 o Java Programming - Beginner to Advanced
 o C Programming - Beginner to Advanced
 o Python Foundation
 o JavaScript Foundation
 + Web Development
 o Full Stack Development with React & Node JS(Live)
 o Java Backend Development(Live)
 o React JS (Basic to Advanced)
 o JavaScript Foundation
 + Machine Learning and Data Science
 o Complete Data Science Program(Live)
 o Mastering Data Analytics
 + School Courses
 o CBSE Class 12 Computer Science
 o School Guide
 + All Courses
 * Tutorials
 + DSA
 + Data Structures
 o Arrays
 o Linked List
 o Stack
 o Queue
 o Binary Tree
 o Binary Search Tree
 o Heap
 o Hashing
 o Graph
 o Advanced Data Structure
 o Matrix
 o Strings
 o All Data Structures
 + Algorithms
 o Analysis of Algorithms
 - Asymptotic Analysis
 - Worst, Average and Best Cases
 - Asymptotic Notations
 - Little o and little omega notations
 - Lower and Upper Bound Theory
 - Analysis of Loops
 - Solving Recurrences
 - Amortized Analysis
 - What does 'Space Complexity' mean ?
 - Pseudo-polynomial Algorithms
 - Polynomial Time Approximation Scheme
 - A Time Complexity Question
 o Searching Algorithms
 o Sorting Algorithms
 o Graph Algorithms
 o Pattern Searching
 o Geometric Algorithms
 o Mathematical
 o Bitwise Algorithms
 o Randomized Algorithms
 o Greedy Algorithms
 o Dynamic Programming
 o Divide and Conquer
 o Backtracking
 o Branch and Bound
 o All Algorithms
 + Interview Corner
 o Company Preparation
 o Top Topics
 o Practice Company Questions
 o Interview Experiences
 o Experienced Interviews
 o Internship Interviews
 o Competitive Programming
 o Design Patterns
 o System Design Tutorial
 o Multiple Choice Quizzes
 + Languages
 o C
 o C++
 o Java
 o Python
 o JavaScript
 o PHP
 o C#
 o SQL
 o Scala
 o Perl
 o Go Language
 o Kotlin
 + Web Development
 o HTML
 o CSS
 o JavaScript
 o PHP
 o CSS Frameworks
 - Bootstrap
 - Tailwind CSS
 - Foundation CSS
 - Materialize CSS
 - Bulma
 - Pure CSS
 - Primer CSS
 - Blaze UI
 - Semantic UI
 o JavaScript Frameworks
 - AngularJS
 - Angular PrimeNG
 - Angular ngx Bootstrap
 - NodeJS
 - Express.js
 o JavaScript Libraries
 - jQuery
 - jQuery Mobile
 - jQuery UI
 - jQuery EasyUI
 - jQWidgets
 - ReactJS
 - React Bootstrap
 - React Rebass
 - React Desktop
 - React Suite
 - ReactJS Evergreen
 - ReactJS Reactstrap
 - Ant Design
 - BlueprintJS
 - p5.js
 - Lodash
 - TensorFlow.js
 - Moment.js
 - Collect.js
 o WordPress
 o JSON
 + School Learning
 o English Grammar
 o School Programming
 o Mathematics
 - Number System
 - Algebra
 - Trigonometry
 - Statistics
 - Probability
 - Geometry
 - Mensuration
 - Calculus
 o Maths Notes (Class 8-12)
 - Class 8 Notes
 - Class 9 Notes
 - Class 10 Notes
 - Class 11 Notes
 - Class 12 Notes
 o NCERT Solutions
 - Class 8 Maths Solution
 - Class 9 Maths Solution
 - Class 10 Maths Solution
 - Class 11 Maths Solution
 - Class 12 Maths Solution
 o RD Sharma Solutions
 - Class 8 Maths Solution
 - Class 9 Maths Solution
 - Class 10 Maths Solution
 - Class 11 Maths Solution
 - Class 12 Maths Solution
 o Physics Notes (Class 8-11)
 - Class 8 Notes
 - Class 9 Notes
 - Class 10 Notes
 - Class 11 Notes
 o Chemistry Notes
 - Class 8 Notes
 - Class 9 Notes
 - Class 10 Notes
 o Business Studies (Class 11th)
 o Business Studies (Class 12th)
 o Accountancy (Class 12th)
 o Statistics for Economics (Class 11th)
 + ML & Data Science
 o Machine Learning
 o Data Science
 + CS Subjects
 o Mathematics
 o Operating System
 o DBMS
 o Computer Networks
 o Computer Organization and Architecture
 o Theory of Computation
 o Compiler Design
 o Digital Logic
 o Software Engineering
 + GATE
 o GATE 2023 Test Series
 o GATE Computer Science Notes
 o Last Minute Notes
 o GATE CS Solved Papers
 o GATE CS Original Papers and Official Keys
 o GATE CS 2023 Syllabus
 o Important Topics for GATE CS
 o GATE 2023 Important Dates
 + Software Designs
 o Software Design Patterns
 o System Design Tutorial
 + GFG Sheets
 o Web Dev Cheat Sheets
 - HTML Cheat Sheet
 - CSS Cheat Sheet
 - Bootstrap Cheat Sheet
 - JS Cheat Sheet
 - jQuery Cheat Sheet
 - Angular Cheat Sheet
 o Company-Wise SDE Sheets
 - Facebook SDE Sheet
 - Amazon SDE Sheet
 - Apple SDE Sheet
 - Netflix SDE Sheet
 - Google SDE Sheet
 - Wipro Coding Sheet
 - Infosys Coding Sheet
 - TCS Coding Sheet
 - Cognizant Coding Sheet
 - HCL Coding Sheet
 o DSA Sheets
 - SDE Sheet
 - FAANG Coding Sheet
 - Love Babbar Sheet
 - Mass Recruiter Sheet
 - Product-Based Coding Sheet
 - Company-Wise Preparation Sheet
 - Array Sheet
 - String Sheet
 - Tree Sheet
 - Graph Sheet
 - DP Sheet
 + CS Exams/PSUs
 o ISRO
 - ISRO CS Original Papers and Official Keys
 - ISRO CS Solved Papers
 - ISRO CS Syllabus for Scientist/Engineer Exam
 o UGC NET
 - UGC NET CS Notes Paper II
 - UGC NET CS Notes Paper III
 - UGC NET CS Solved Papers
 + Student
 o Campus Ambassador Program
 o School Ambassador Program
 o Project
 o Geek of the Month
 o Campus Geek of the Month
 o Placement Course
 o Competitive Programming
 o Testimonials
 o Student Chapter
 o Geek on the Top
 o Internship
 o Careers
 + UPSC
 o Geography Notes
 o History Notes
 o Science & Tech. Notes
 o Ethics Notes
 o Polity Notes
 o Economics Notes
 o UPSC Previous Year Papers
 + SSC CGL
 o SSC CGL Syllabus
 o General Studies
 o English
 o Reasoning
 o Subjectwise Practice Papers
 o Previous Year Papers
 + Banking Exams
 o SBI Clerk
 - SBI Clerk Syllabus
 - General Awareness
 - English
 - Quantitative Aptitude
 - Reasoning Ability
 - SBI Clerk Practice Papers
 o SBI PO
 - SBI PO Syllabus
 - General Awareness
 - English
 - Quantitative Aptitude
 - Reasoning Ability
 - Previous Year Papers
 - SBI PO Practice Papers
 o IBPS PO
 - IBPS PO 2022 Syllabus
 - English Notes
 - Reasoning Notes
 - Previous Year Papers
 - Mock Question Papers
 o IBPS Clerk
 - IBPS Clerk Syllabus
 - English Notes
 - Previous Year Papers
 * Jobs
 + Apply for a Job
 + Apply through Jobathon
 + Post a Job
 + Hire through Jobathon
 * Practice
 + All DSA Problems
 + Problem of the Day
 + GFG SDE Sheet
 + Curated DSA Lists
 o Top 50 Array Problems
 o Top 50 String Problems
 o Top 50 Tree Problems
 o Top 50 Graph Problems
 o Top 50 DP Problems
 * Contests
 + GFG Weekly Coding Contest
 + Job-A-Thon: Hiring Challenge
 + BiWizard School Contest
 + All Contests and Events
 * 
 * 
 * 
 * Home
 * Saved Videos
 * Courses
 * 
 * GBlog
 * Puzzles
 * What's New ?
 Change Language
 * Data Structures and Algorithms
 * Interview Preparation
 * Data Science
 * Topic-wise Practice
 * C
 * C++
 * Java
 * Python
 * Latest Blogs
 * Competitive Programming
 * JavaScript
 * Machine Learning
 * Write & Earn
 * Web Development
 * Puzzles
 * Projects
 Related Articles
▲
 Open in App
 Not now

 Related Articles

 Write an Article
 * Write an Interview Experience
 * Error Handling in Compiler Design
 * Error detection and Recovery in Compiler
 * Linker
 * Difference between Linker and Loader
 * Loader in C/C++
 * Developing a Linux based shell
 * Making your own Linux Shell in C
 * Zillious Interview Experience | Set 2 (On-Campus)
 * Zillious Interview Experience | Set 1 (On-Campus)
 * Zillious Interview Experience | Set 3 (On-Campus)
 * Shell Technology Centre Bangalore Interview Experience (On-Campus for Software Engineer)
 * Shell India Interview Experience
 * Shell India Interview Experience (IT)
 * Shell India – Campus Placements 2019
 * SHELL On-Campus Recruitment for SDE
 * Shell Interview Experience | On-Campus
 * Shell Interview Experience for SDE (On-Campus)
 * Interesting Commands on Mac Terminal
 * Basic System Controls with Terminal in Linux
 * Basic Linux Commands for day to day life
 * Linux Commands
 * Essential Linux/Unix Commands
 * Basic Shell Commands in Linux
 * Language Processors: Assembler, Compiler and Interpreter
 * Generation of Programming Languages
 Write an Article
 * Write an Interview Experience
 * Arrays in C/C++
 * Dynamic Memory Allocation in C using malloc(), calloc(), free() and realloc()
 * std::sort() in C++ STL
 * Bitwise Operators in C/C++
 * Core Dump (Segmentation fault) in C/C++
 Write an Article
 * Write an Interview Experience
 * Error Handling in Compiler Design
 * Error detection and Recovery in Compiler
 * Linker
 * Difference between Linker and Loader
 * Loader in C/C++
 * Developing a Linux based shell
 * Making your own Linux Shell in C
 * Zillious Interview Experience | Set 2 (On-Campus)
 * Zillious Interview Experience | Set 1 (On-Campus)
 * Zillious Interview Experience | Set 3 (On-Campus)
 * Shell Technology Centre Bangalore Interview Experience (On-Campus for Software Engineer)
 * Shell India Interview Experience
 * Shell India Interview Experience (IT)
 * Shell India – Campus Placements 2019
 * SHELL On-Campus Recruitment for SDE
 * Shell Interview Experience | On-Campus
 * Shell Interview Experience for SDE (On-Campus)
 * Interesting Commands on Mac Terminal
 * Basic System Controls with Terminal in Linux
 * Basic Linux Commands for day to day life
 * Linux Commands
 * Essential Linux/Unix Commands
 * Basic Shell Commands in Linux
 * Language Processors: Assembler, Compiler and Interpreter
 * Generation of Programming Languages
 Write an Article
 * Write an Interview Experience
 * Arrays in C/C++
 * Dynamic Memory Allocation in C using malloc(), calloc(), free() and realloc()
 * std::sort() in C++ STL
 * Bitwise Operators in C/C++
 * Core Dump (Segmentation fault) in C/C++

 Making your own Linux Shell in C

 Improve Article
 Save Article
 * Difficulty Level : Medium
 * Last Updated : 07 Jun, 2020
 * Read
 * Discuss(20+)
 Improve Article
 Save Article

 To know more about what a shell is, click here.

 We all use the built in terminal window in Linux distributions like Ubuntu, Fedora, etc. But how do they actually work? In this article, We are going to handle some under the hood features and algorithms what actually work inside a shell. All Linux operating systems have a terminal window to write in commands. But how are they executed properly after they are entered?
 Also, how are extra features like keeping the history of commands and showing help handled? All of this can be understood by creating your own shell.


 The Basics

 After a command is entered, the following things are done:

 1. Command is entered and if length is non-null, keep it in history.
 2. Parsing : Parsing is the breaking up of commands into individual words and strings
 3. Checking for special characters like pipes, etc is done
 4. Checking if built-in commands are asked for.
 5. If pipes are present, handling pipes.
 6. Executing system commands and libraries by forking a child and calling execvp.
 7. Printing current directory name and asking for next input.

 For keeping history of commands, recovering history using arrow keys and handling autocomplete using the tab key, we will be using the readline library provided by GNU.

 Implementation

 To install the readline library, open the terminal window and write

 sudo apt-get install libreadline-dev

 It will ask for your password. Enter it. Press y in the next step.

 * Printing the directory can be done using getcwd.
 * Getting user name can be done by getenv(“USER”)
 * Parsing can be done by using strsep(“”). It will separate words based on spaces. Always skip words with zero length to avoid storing of extra spaces.
 * After parsing, check the list of built-in commands, and if present, execute it. If not, execute it as a system command. To check for built-in commands, store the commands in an array of character pointers, and compare all with strcmp().
 Note: “cd” does not work natively using execvp, so it is a built-in command, executed with chdir().
 * For executing a system command, a new child will be created and then by using the execvp, execute the command, and wait until it is finished.
 * Detecting pipes can also be done by using strsep(“|”).To handle pipes, first separate the first part of the command from the second part. Then after parsing each part, call both parts in two separate new children, using execvp. Piping means passing the output of first command as the input of second command.
 1. Declare an integer array of size 2 for storing file descriptors. File descriptor 0 is for reading and 1 is for writing.
 2. Open a pipe using the pipe() function.
 3. Create two children.
 4. In child 1->
 Here the output has to be taken into the pipe.
 Copy file descriptor 1 to stdout.
 Close file descriptor 0.
 Execute the first command using execvp()
 
 5. In child 2->
 Here the input has to be taken from the pipe.
 Copy file descriptor 0 to stdin.
 Close file descriptor 1.
 Execute the second command using execvp()
 
 6. Wait for the two children to finish in the parent.




 // C Program to design a shell in Linux 
 #include<stdio.h> 
 #include<string.h> 
 #include<stdlib.h> 
 #include<unistd.h> 
 #include<sys/types.h> 
 #include<sys/wait.h> 
 #include<readline/readline.h> 
 #include<readline/history.h> 
 #define MAXCOM 1000 // max number of letters to be supported 
 #define MAXLIST 100 // max number of commands to be supported 
 // Clearing the shell using escape sequences 
 #define clear() printf("\033[H\033[J") 
 // Greeting shell during startup 
 void init_shell() 
 { 
 clear(); 
 printf("\n\n\n\n******************" 
 "************************"); 
 printf("\n\n\n\t****MY SHELL****"); 
 printf("\n\n\t-USE AT YOUR OWN RISK-"); 
 printf("\n\n\n\n*******************" 
 "***********************"); 
 char* username = getenv("USER"); 
 printf("\n\n\nUSER is: @%s", username); 
 printf("\n"); 
 sleep(1); 
 clear(); 
 } 
 // Function to take input 
 int takeInput(char* str) 
 { 
 char* buf; 
 buf = readline("\n>>> "); 
 if (strlen(buf) != 0) { 
 add_history(buf); 
 strcpy(str, buf); 
 return 0; 
 } else { 
 return 1; 
 } 
 } 
 // Function to print Current Directory. 
 void printDir() 
 { 
 char cwd[1024]; 
 getcwd(cwd, sizeof(cwd)); 
 printf("\nDir: %s", cwd); 
 } 
 // Function where the system command is executed 
 void execArgs(char** parsed) 
 { 
 // Forking a child 
 pid_t pid = fork(); 
 if (pid == -1) { 
 printf("\nFailed forking child.."); 
 return; 
 } else if (pid == 0) { 
 if (execvp(parsed[0], parsed) < 0) { 
 printf("\nCould not execute command.."); 
 } 
 exit(0); 
 } else { 
 // waiting for child to terminate 
 wait(NULL); 
 return; 
 } 
 } 
 // Function where the piped system commands is executed 
 void execArgsPiped(char** parsed, char** parsedpipe) 
 { 
 // 0 is read end, 1 is write end 
 int pipefd[2]; 
 pid_t p1, p2; 
 if (pipe(pipefd) < 0) { 
 printf("\nPipe could not be initialized"); 
 return; 
 } 
 p1 = fork(); 
 if (p1 < 0) { 
 printf("\nCould not fork"); 
 return; 
 } 
 if (p1 == 0) { 
 // Child 1 executing.. 
 // It only needs to write at the write end 
 close(pipefd[0]); 
 dup2(pipefd[1], STDOUT_FILENO); 
 close(pipefd[1]); 
 if (execvp(parsed[0], parsed) < 0) { 
 printf("\nCould not execute command 1.."); 
 exit(0); 
 } 
 } else { 
 // Parent executing 
 p2 = fork(); 
 if (p2 < 0) { 
 printf("\nCould not fork"); 
 return; 
 } 
 // Child 2 executing.. 
 // It only needs to read at the read end 
 if (p2 == 0) { 
 close(pipefd[1]); 
 dup2(pipefd[0], STDIN_FILENO); 
 close(pipefd[0]); 
 if (execvp(parsedpipe[0], parsedpipe) < 0) { 
 printf("\nCould not execute command 2.."); 
 exit(0); 
 } 
 } else { 
 // parent executing, waiting for two children 
 wait(NULL); 
 wait(NULL); 
 } 
 } 
 } 
 // Help command builtin 
 void openHelp() 
 { 
 puts("\n***WELCOME TO MY SHELL HELP***" 
 "\nCopyright @ Suprotik Dey" 
 "\n-Use the shell at your own risk..." 
 "\nList of Commands supported:" 
 "\n>cd" 
 "\n>ls" 
 "\n>exit" 
 "\n>all other general commands available in UNIX shell" 
 "\n>pipe handling" 
 "\n>improper space handling"); 
 return; 
 } 
 // Function to execute builtin commands 
 int ownCmdHandler(char** parsed) 
 { 
 int NoOfOwnCmds = 4, i, switchOwnArg = 0; 
 char* ListOfOwnCmds[NoOfOwnCmds]; 
 char* username; 
 ListOfOwnCmds[0] = "exit"; 
 ListOfOwnCmds[1] = "cd"; 
 ListOfOwnCmds[2] = "help"; 
 ListOfOwnCmds[3] = "hello"; 
 for (i = 0; i < NoOfOwnCmds; i++) { 
 if (strcmp(parsed[0], ListOfOwnCmds[i]) == 0) { 
 switchOwnArg = i + 1; 
 break; 
 } 
 } 
 switch (switchOwnArg) { 
 case 1: 
 printf("\nGoodbye\n"); 
 exit(0); 
 case 2: 
 chdir(parsed[1]); 
 return 1; 
 case 3: 
 openHelp(); 
 return 1; 
 case 4: 
 username = getenv("USER"); 
 printf("\nHello %s.\nMind that this is " 
 "not a place to play around." 
 "\nUse help to know more..\n", 
 username); 
 return 1; 
 default: 
 break; 
 } 
 return 0; 
 } 
 // function for finding pipe 
 int parsePipe(char* str, char** strpiped) 
 { 
 int i; 
 for (i = 0; i < 2; i++) { 
 strpiped[i] = strsep(&str, "|"); 
 if (strpiped[i] == NULL) 
 break; 
 } 
 if (strpiped[1] == NULL) 
 return 0; // returns zero if no pipe is found. 
 else { 
 return 1; 
 } 
 } 
 // function for parsing command words 
 void parseSpace(char* str, char** parsed) 
 { 
 int i; 
 for (i = 0; i < MAXLIST; i++) { 
 parsed[i] = strsep(&str, " "); 
 if (parsed[i] == NULL) 
 break; 
 if (strlen(parsed[i]) == 0) 
 i--; 
 } 
 } 
 int processString(char* str, char** parsed, char** parsedpipe)
 { 
 char* strpiped[2]; 
 int piped = 0; 
 piped = parsePipe(str, strpiped); 
 if (piped) { 
 parseSpace(strpiped[0], parsed); 
 parseSpace(strpiped[1], parsedpipe); 
 } else { 
 parseSpace(str, parsed); 
 } 
 if (ownCmdHandler(parsed)) 
 return 0; 
 else 
 return 1 + piped; 
 } 
 int main() 
 { 
 char inputString[MAXCOM], *parsedArgs[MAXLIST]; 
 char* parsedArgsPiped[MAXLIST]; 
 int execFlag = 0; 
 init_shell(); 
 while (1) { 
 // print shell line 
 printDir(); 
 // take input 
 if (takeInput(inputString)) 
 continue; 
 // process 
 execFlag = processString(inputString, 
 parsedArgs, parsedArgsPiped); 
 // execflag returns zero if there is no command 
 // or it is a builtin command, 
 // 1 if it is a simple command 
 // 2 if it is including a pipe. 
 // execute 
 if (execFlag == 1) 
 execArgs(parsedArgs); 
 if (execFlag == 2) 
 execArgsPiped(parsedArgs, parsedArgsPiped); 
 } 
 return 0; 
 } 
 

 To Run the code –

 gcc shell.c -lreadline
 ./a.out 

 Output:


 This article is contributed by Suprotik Dey. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

 Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.


 My Personal Notes arrow_drop_up
 Save

 Please Login to comment...

 Like

 Previous
 Developing a Linux based shell
 Next
 Zillious Interview Experience | Set 2 (On-Campus)
 Related Articles
 1. Shell Script to Show the Difference Between echo “$SHELL” and echo ‘$SHELL’
 2. Shell Scripting - Difference between Korn Shell and Bash shell
 3. Introduction to Linux Shell and Shell Scripting
 4. Auto Logout in Linux Shell Using TMOUT Shell Variable
 5. How to protect Linux shell file using noclobber in bash shell?
 6. How to Build Your Own Commands in Linux?
 7. How to Code Your Own Port Scanner Using BASH Script and netcat Tool in Linux?
 8. Shell Scripting - Decision Making
 9. Shell Scripting - Restricted Shell
 10. Shell Script to Demonstrate the Use of Shell Function Library
 Article Contributed By :
 GeeksforGeeks
 Vote for difficulty
 Current difficulty : Medium


 Easy Normal Medium Hard Expert

 Improved By :
 * top_gunn
 Article Tags :
 * system-programming
 * C Language
 * Linux-Unix
 Report Issue
 What's New
 C Programming - Self Paced Course
 View Details
 Complete Interview Preparation Course
 View Details
 Master Data Science & ML
 View Details
 System Design- Live Classes
 View Details

 Improve your Coding Skills with Practice

 Try It!
 A-143, 9th Floor, Sovereign Corporate Tower,
 Sector-136, Noida, Uttar Pradesh - 201305
 feedback@geeksforgeeks.org
 * Company
 * About Us
 * Careers
 * In Media
 * Contact Us
 * Privacy Policy
 * Copyright Policy
 * Advertise with us
 * Learn
 * DSA
 * Algorithms
 * Data Structures
 * SDE Cheat Sheet
 * Machine learning
 * CS Subjects
 * Video Tutorials
 * Courses
 * News
 * Top News
 * Technology
 * Work & Career
 * Business
 * Finance
 * Lifestyle
 * Knowledge
 * Languages
 * Python
 * Java
 * CPP
 * Golang
 * C#
 * SQL
 * Kotlin
 * Web Development
 * Web Tutorials
 * Django Tutorial
 * HTML
 * JavaScript
 * Bootstrap
 * ReactJS
 * NodeJS
 * Contribute
 * Write an Article
 * Improve an Article
 * Pick Topics to Write
 * Write Interview Experience
 * Internships
 * Video Internship
 @geeksforgeeks , Some rights reserved
 We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy Got It !

 Start Your Coding Journey Now!

 Login Register
#include&lt;stdio.h&gt;   #include&lt;string.h&gt;   #include&lt;stdlib.h&gt;   #include&lt;unistd.h&gt;   #include&lt;sys/types.h&gt;   #include&lt;sys/wait.h&gt;   #include&lt;readline/readline.h&gt;   #include&lt;readline/history.h&gt;   #define MAXCOM 1000 // max number of letters to be supported   #define MAXLIST 100 // max number of commands to be supported   #define clear() printf("\033[H\033[J")   void init_shell()   {        clear();        printf ( "\n\n\n\n******************"            "************************" );        printf ( "\n\n\n\t****MY SHELL****" );        printf ( "\n\n\t-USE AT YOUR OWN RISK-" );        printf ( "\n\n\n\n*******************"            "***********************" );        char * username =  getenv ( "USER" );        printf ( "\n\n\nUSER is: @%s" , username);        printf ( "\n" );        sleep(1);        clear();   }   int takeInput( char * str)   {        char * buf;        buf = readline( "\n&gt;&gt;&gt; " );        if ( strlen (buf) != 0) {            add_history(buf);            strcpy (str, buf);            return 0;        }  else {            return 1;        }   }   void printDir()   {        char cwd[1024];        getcwd(cwd,  sizeof (cwd));        printf ( "\nDir: %s" , cwd);   }   void execArgs( char ** parsed)   {        pid_t pid = fork();         if (pid == -1) {            printf ( "\nFailed forking child.." );            return ;        }  else if (pid == 0) {            if (execvp(parsed[0], parsed) &lt; 0) {                printf ( "\nCould not execute command.." );            }            exit (0);        }  else {            wait(NULL);             return ;        }   }   void execArgsPiped( char ** parsed,  char ** parsedpipe)   {        int pipefd[2];         pid_t p1, p2;        if (pipe(pipefd) &lt; 0) {            printf ( "\nPipe could not be initialized" );            return ;        }        p1 = fork();        if (p1 &lt; 0) {            printf ( "\nCould not fork" );            return ;        }        if (p1 == 0) {            close(pipefd[0]);            dup2(pipefd[1], STDOUT_FILENO);            close(pipefd[1]);            if (execvp(parsed[0], parsed) &lt; 0) {                printf ( "\nCould not execute command 1.." );                exit (0);            }        }  else {            p2 = fork();            if (p2 &lt; 0) {                printf ( "\nCould not fork" );                return ;            }            if (p2 == 0) {                close(pipefd[1]);                dup2(pipefd[0], STDIN_FILENO);                close(pipefd[0]);                if (execvp(parsedpipe[0], parsedpipe) &lt; 0) {                    printf ( "\nCould not execute command 2.." );                    exit (0);                }            }  else {                wait(NULL);                wait(NULL);            }        }   }   void openHelp()   {        puts ( "\n***WELCOME TO MY SHELL HELP***"            "\nCopyright @ Suprotik Dey"            "\n-Use the shell at your own risk..."            "\nList of Commands supported:"            "\n&gt;cd"            "\n&gt;ls"            "\n&gt;exit"            "\n&gt;all other general commands available in UNIX shell"            "\n&gt;pipe handling"            "\n&gt;improper space handling" );        return ;   }   int ownCmdHandler( char ** parsed)   {        int NoOfOwnCmds = 4, i, switchOwnArg = 0;        char * ListOfOwnCmds[NoOfOwnCmds];        char * username;        ListOfOwnCmds[0] =  "exit" ;        ListOfOwnCmds[1] =  "cd" ;        ListOfOwnCmds[2] =  "help" ;        ListOfOwnCmds[3] =  "hello" ;        for (i = 0; i &lt; NoOfOwnCmds; i++) {            if ( strcmp (parsed[0], ListOfOwnCmds[i]) == 0) {                switchOwnArg = i + 1;                break ;            }        }        switch (switchOwnArg) {        case 1:            printf ( "\nGoodbye\n" );            exit (0);        case 2:            chdir(parsed[1]);            return 1;        case 3:            openHelp();            return 1;        case 4:            username =  getenv ( "USER" );            printf ( "\nHello %s.\nMind that this is "                "not a place to play around."                "\nUse help to know more..\n" ,                username);            return 1;        default :            break ;        }        return 0;   }   int parsePipe( char * str,  char ** strpiped)   {        int i;        for (i = 0; i &lt; 2; i++) {            strpiped[i] = strsep(&amp;str,  "|" );            if (strpiped[i] == NULL)                break ;        }        if (strpiped[1] == NULL)            return 0;         else {            return 1;        }   }   void parseSpace( char * str,  char ** parsed)   {        int i;        for (i = 0; i &lt; MAXLIST; i++) {            parsed[i] = strsep(&amp;str,  " " );            if (parsed[i] == NULL)                break ;            if ( strlen (parsed[i]) == 0)                i--;        }   }   int processString( char * str,  char ** parsed,  char ** parsedpipe)   {        char * strpiped[2];        int piped = 0;        piped = parsePipe(str, strpiped);        if (piped) {            parseSpace(strpiped[0], parsed);            parseSpace(strpiped[1], parsedpipe);        }  else {            parseSpace(str, parsed);        }        if (ownCmdHandler(parsed))            return 0;        else            return 1 + piped;   }   int main()   {        char inputString[MAXCOM], *parsedArgs[MAXLIST];        char * parsedArgsPiped[MAXLIST];        int execFlag = 0;        init_shell();        while (1) {            printDir();            if (takeInput(inputString))                continue ;            execFlag = processString(inputString,            parsedArgs, parsedArgsPiped);            if (execFlag == 1)                execArgs(parsedArgs);            if (execFlag == 2)                execArgsPiped(parsedArgs, parsedArgsPiped);        }        return 0;   }
Making your own Linux Shell in C - GeeksforGeeks
https://www.geeksforgeeks.org/making-linux-shell-c/
https://jvns.ca/blog/2013/09/30/hacker-school-day-2-what-does-a-shell-even-do/
Day 1: What does a shell even do?
2013-09-30
Julia Evans
<div><div>
 <p>So I’m working on writing a shell in C a little bit. Before yesterday, I
didn’t have a very clear idea of what writing a shell even <em>meant</em>. Here
are some things that your shell has to do! I’m sure there are some
Important Things missing.</p>
<ul>
<li>Parse what you type in to figure out which are the commands and which
are the arguments (<code>ls -la LICENSE</code>)</li>
<li>expand <code>ls *</code> into <code>ls file1 file2 file3 ...</code></li>
<li>Pipes! If you write <code>ls | grep blah</code>, it needs to send the output from
<code>ls</code> into <code>grep</code>. And redirection too.</li>
<li>Signal handling! If you press <code>Ctrl+C</code>, it needs to send that signal
to whatever process you’re running. Or something. I don’t really
understand this yet.</li>
<li>Process management! Lets you background and foreground jobs. (<code>Ctrl+z</code>
and <code>fg</code> and <code>bg</code>)</li>
<li>Shell scripting! (for loops and things)</li>
</ul>
<p>And a thing the shell <em>doesn’t</em> have to do:</p>
<ul>
<li>Figure out which command to execute using the <code>$PATH</code> environment
variable. <code>exec</code> does that, apparently.</li>
</ul>
<p>I think I’m going to work on implementing pipes &amp; redirection &amp; signal
handling.</p>
</div>||||I|||| Julia Evans

 * About
 * Talks
 * Projects
 * Twitter
 * Mastodon
 * Github
 * Favorites
 * Zines
 * RSS

 Day 1: What does a shell even do?

 • hackerschool •

 So I’m working on writing a shell in C a little bit. Before yesterday, I didn’t have a very clear idea of what writing a shell even meant. Here are some things that your shell has to do! I’m sure there are some Important Things missing.

 * Parse what you type in to figure out which are the commands and which are the arguments (ls -la LICENSE)
 * expand ls * into ls file1 file2 file3 ...
 * Pipes! If you write ls | grep blah, it needs to send the output from ls into grep. And redirection too.
 * Signal handling! If you press Ctrl+C, it needs to send that signal to whatever process you’re running. Or something. I don’t really understand this yet.
 * Process management! Lets you background and foreground jobs. (Ctrl+z and fg and bg)
 * Shell scripting! (for loops and things)

 And a thing the shell doesn’t have to do:

 * Figure out which command to execute using the $PATH environment variable. exec does that, apparently.

 I think I’m going to work on implementing pipes & redirection & signal handling.

 Want a weekly digest of this blog? Subscribe

 Hacker School Day 1: Messing around with the stack in C Day 2: netcat fun!

 Archives
 © Julia Evans. If you like this, you may like Ulia Ea or, more seriously, this list of blogs I love or some books I've read .

 You might also like the Recurse Center, my very favorite programming community (my posts about it)

So I’m working on writing a shell in C a little bit. Before yesterday, I
didn’t have a very clear idea of what writing a shell even meant. Here
are some things that your shell has to do! I’m sure there are some
Important Things missing.
Parse what you type in to figure out which are the commands and which
are the arguments (ls -la LICENSE)
expand ls * into ls file1 file2 file3 ... 
Pipes! If you write ls | grep blah, it needs to send the output from
ls into grep. And redirection too.
Signal handling! If you press Ctrl+C, it needs to send that signal
to whatever process you’re running. Or something. I don’t really
understand this yet.
Process management! Lets you background and foreground jobs. (Ctrl+z
and fg and bg)
Shell scripting! (for loops and things)
And a thing the shell doesn’t have to do:
Figure out which command to execute using the $PATH environment
variable. exec does that, apparently.
I think I’m going to work on implementing pipes &amp; redirection &amp; signal
handling.
Day 1: What does a shell even do?
https://www.jvns.ca/blog/2013/09/30/hacker-school-day-2-what-does-a-shell-even-do/
https://stackoverflow.com/questions/29762189/how-to-execute-bash-commands-from-c
How to execute bash commands from C?
2015-04-21
Tarabyte Tarabyte
<div><div>
 
<div>
 
 
<div>
 
 <div>
 
<p>Is there a way to run command line utilities, e.g. <code>gzip</code>, into a C app?</p>
 </div>
 
 <div>
 <p>
 asked Apr 20, 2015 at 23:27
 </p>
 <div>
 <a href="/users/476410/tarabyte"><p></p></a>
 </div>
 <div>
 <p><a href="/users/476410/tarabyte">tarabyte</a>tarabyte</p><p>17.1k14 gold badges72 silver badges112 bronze badges
 </p>
 </div>
</div>
 
</div>
 <p>2</p>
 </div>
 <div>
 <div>
 <p>
 </p><h2>
 1 Answer
 
 </h2>
 <p></p>
 
 </div>
 
 <h2>
 
 </h2>
 </div>
 </div>||||I|||| Stack Overflow
 1. About
 2. Products
 3. For Teams
 1. Stack Overflow Public questions & answers
 2. Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
 3. Talent Build your employer brand
 4. Advertising Reach developers & technologists worldwide
 5. About the company
 Loading…

 1. current community

 + Stack Overflow
 help chat
 + Meta Stack Overflow

 your communities

 Sign up or log in to customize your list.

 more stack exchange communities

 company blog
 2. 
 3. Log in
 4. Sign up
 1. Home
 2. 
 1. Public
 2. Questions
 3. Tags
 4. Users
 5. Companies
 6. Collectives
 7. Explore Collectives
 3. 
 1. Teams
 Stack Overflow for Teams – Start collaborating and sharing organizational knowledge. Create a free Team Why Teams?
 2. Teams
 3. Create free Team

 Collectives™ on Stack Overflow

 Find centralized, trusted content and collaborate around the technologies you use most.

 Learn more about Collectives

 Teams

 Q&A for work

 Connect and share knowledge within a single location that is structured and easy to search.

 Learn more about Teams

 How to execute bash commands from C? [duplicate]

 Ask Question
 Asked 7 years, 9 months ago
 Modified 7 years, 9 months ago
 Viewed 97k times
 21
 This question already has answers here:
 How to execute a shell script from C in Linux? (6 answers)
 Closed 7 years ago .

 Is there a way to run command line utilities, e.g. gzip, into a C app?

 * bash
 * c
 * gzip
 Share
 Follow
 asked Apr 20, 2015 at 23:27
 tarabyte tarabyte
 17.1k 14 14 gold badges 72 72 silver badges 112 112 bronze badges
 2
 * why not just use the c library for (de)compression (zlib)?
 – jayhendren
 Apr 20, 2015 at 23:31
 * 1
 If you run it as a "bash command", a la system(), you're doing it wrong. Direct invocation with an exec-family syscall is more efficient and less prone to bugs.
 – Charles Duffy
 Apr 21, 2015 at 4:30
 Add a comment |

 1 Answer

 Sorted by: Reset to default
 Highest score (default) Trending (recent votes count more) Date modified (newest first) Date created (oldest first)
 40

 Use system():

 #include <stdlib.h>
 int status = system("gzip foo");
 

 See the man page (man 3 system) for more detailed information on how to use it.

 By the way, this question already has an answer here: How do I execute external program within C code in linux with arguments?

 Share
 Follow
 edited May 23, 2017 at 11:47
 Community Bot
 1 1 1 silver badge
 answered Apr 20, 2015 at 23:39
 jayhendren jayhendren
 4,127 1 1 gold badge 35 35 silver badges 56 56 bronze badges
 3
 * 3
 See: Why to avoid system() function in c/c++ . Instead look at the execl family of functions.
 – David C. Rankin
 Apr 21, 2015 at 4:28
 * man system # seems to default to 3
 – jasonleonhard
 Feb 12, 2021 at 4:42
 * No entry for system in section 1 of the manual No entry for system in section 2 of the manual so starts at 3
 – jasonleonhard
 Feb 12, 2021 at 4:43
 Add a comment |

 Not the answer you're looking for? Browse other questions tagged
 * bash
 * c
 * gzip
 or ask your own question.

 * The Overflow Blog
 * Announcing more ways to learn and grow your skills
 * Why developer experience is the key to better software, straight from the...
 * Featured on Meta
 * Accessibility Update: Colors
 * 2022: a year in moderation
 * Collectives: The next iteration
 * We’re bringing advertisements for technology courses to Stack Overflow
 * Temporary policy: ChatGPT is banned

 Linked

 70
 How to execute a shell script from C in Linux?
 22
 Why should the system() function be avoided in C and C++?

 Related

 4281
 How do I check if a directory exists or not in a Bash shell script?
 5980
 How do I get the directory where a Bash script is located from within the script itself?
 3345
 How to check if a string contains a substring in Bash
 2941
 How can I check if a program exists from a Bash script?
 3843
 How do I tell if a file does not exist in Bash?
 1679
 How to convert a string to lower case in Bash
 1203
 How to echo shell commands as they are executed
 3400
 How to concatenate string variables in Bash
 2295
 How do I set a variable to the output of a command in Bash?
 3299
 Echo newline in Bash prints literal \n

 Hot Network Questions

 * Eyes stay stationary while posing rest of the mesh
 * Stable words in the Proto-Indo-European language family
 * How to clean bath spa nozzles?
 * The word "decant" for clone generation
 * Which Deep Learning Method to use for the classification of precious stones (diamonds, sapphire, ruby etc) based on digital photo images and data set?
 * Inconsistent interline spacing in enumitem
 * Why are the trailing edges of wings not always made as 'sharp' as possible?
 * Can a helicopter's main rotor mince a human?
 * Select applied to multiple objects
 * If Sauron wins eventually without the Ring, why weren't Elrond/Gandalf in panic mode before Frodo showed up?
 * Both "fēmina" and "mulier" mean "woman": what's the difference?
 * Table of unequal sequence
 * Gamma uncertainty set
 * I forgot to include $10 in interest in my tax return. My tax liability did not change. Should I file an amended return?
 * Polynomial approximation of max function
 * (Rev. 2) Command-line Tower of Hanoi game
 * Do famous people really have the power to ruin the career of unrelated researchers?
 * Can "né" or "née" be used to refer to a religious's secular name?
 * I need a seemingly large battery for project containing several sensors, what should I do?
 * How can one order cheeses for a cheese tasting event?
 * Why do Pokemon sometimes have dark stripes in Pokemon Go?
 * What changes to Voyager could have been made?
 * Ada and its candidate languages
 * Addition and multiplication are commutative but exponentiation and tetration are not. Do we know why?
 more hot questions

 Stack Overflow

 * Questions
 * Help

 Products

 * Teams
 * Advertising
 * Collectives
 * Talent

 Company

 * About
 * Press
 * Work Here
 * Legal
 * Privacy Policy
 * Terms of Service
 * Contact Us
 * Cookie Settings
 * Cookie Policy

 Stack Exchange Network

 * Technology
 * Culture & recreation
 * Life & arts
 * Science
 * Professional
 * Business
 * API
 * Data
 * Blog
 * Facebook
 * Twitter
 * LinkedIn
 * Instagram

 Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA. rev 2023.2.3.43216

 Your privacy

 By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

 Accept all cookies Customize settings
Is there a way to run command line utilities, e.g. gzip, into a C app?
 
 
 
 
 asked Apr 20, 2015 at 23:27
 
 
    
 
 
  tarabytetarabyte 17.1k14 gold badges72 silver badges112 bronze badges
 
 
 
 2
 
 
 
 
  
 1 Answer
How to execute bash commands from C?
https://stackoverflow.com/questions/29762189/how-to-execute-bash-commands-from-c
https://www.unix.com/programming/216190-putting-bash-script-c-program.html
Putting bash script in C program
2013-02-17
None
<div><div>
 <div>
<p>
</p><h2>10 More Discussions You Might Find Interesting</h2>
<p></p>
</div>
<div>
<p></p><h2>1. UNIX for Beginners Questions &amp; Answers</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/unix-for-beginners-questions-and-answers/281929-pass-regex-java-program-bash-script.html?s=1aa398b618623ab68a008d5fc8b369b0">Pass RegEx to java program in bash script</a>
</h2><p></p>
<p>I can't seem to get this right. I've tried it every way imaginable using every trick I see on stackexchange and such. No luck. So nothing major here, something like: 
 
 
#!/bin/bash 
 
SEARCH="ARG1 ARG2 '((^EXACT$)|(.*InTheMiddle*)|(^AtBeginning*))'" 
java -cp /my/class/path MyClassName $SEARCH... (3 Replies)</p>
<p></p><h5>Discussion started by: stonkers</h5><p></p>
</div>
<div>
<p></p><h2>2. Programming</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/programming/274298-program-bash-script-see-total-progress-copy.html?s=1aa398b618623ab68a008d5fc8b369b0">Program or bash script to see total progress of copy</a>
</h2><p></p>
<p>hi all, 
 
i want a program or to make a bash script to find out the total ETA/percent (would be nice aswell a progress bar) of a copy recursive command 
 
so lets say i do - 
 
cp -r /source_folder/ /destinatation_folder/ 
 
and when i run it i get no information on the screen of how the copy is... (20 Replies)</p>
<p></p><h5>Discussion started by: robertkwild</h5><p></p>
</div>
<div>
<p></p><h2>3. Shell Programming and Scripting</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/shell-programming-and-scripting/252240-help-bash-shell-script-spell-checker-program.html?s=1aa398b618623ab68a008d5fc8b369b0">Help with Bash Shell Script Spell Checker program.</a>
</h2><p></p>
<p>I have a majority of this problem done but seem to be struggling on the last couple of steps. Here is the whole problem to help you guys get a better understanding. 
 
Write a shell script that implements a simple spell checker. 
The filename you will use for your script will be your Z-id followed... (1 Reply)</p>
<p></p><h5>Discussion started by: DsmRacer2k14</h5><p></p>
</div>
<div>
<p></p><h2>4. UNIX for Dummies Questions &amp; Answers</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/unix-for-dummies-questions-and-answers/242036-running-c-c-program-bash-script-server.html?s=1aa398b618623ab68a008d5fc8b369b0">Running a C/C++ program and/or bash script from a server</a>
</h2><p></p>
<p>I wish to be able to give to a client the opportunity to : 
 
0) Turn one of my ubuntu computers into a webserver 
1) See a webpage after visiting a url where an external user/client can set a couple of variables (e.g. Number1= ?, Number2=?) 
2) By pressing "run" the program runs on my machine 
3)... (1 Reply)</p>
<p></p><h5>Discussion started by: frad</h5><p></p>
</div>
<div>
<p></p><h2>5. Shell Programming and Scripting</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/shell-programming-and-scripting/233428-putting-separator-file-using-awk-bash.html?s=1aa398b618623ab68a008d5fc8b369b0">Putting a separator in file using awk/bash</a>
</h2><p></p>
<p>I have a file with the following content: 
a-123-345-232 
a-23343-4545-545 
a-67676-45454-8787 
a-129-8912-9824 
b-564-78678-2322 
b-5454-76767-8899 
b-85554-124-152-29 
c-34534-654543-323 
(... and so on, actually these are pretty huge records) 
Now, I want that the file should not be broken in to... (8 Replies)</p>
<p></p><h5>Discussion started by: askerbis</h5><p></p>
</div>
<div>
<p></p><h2>6. Shell Programming and Scripting</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/shell-programming-and-scripting/189901-bash-script-start-program-answer-prompts.html?s=1aa398b618623ab68a008d5fc8b369b0">Bash script to start program and answer prompts?</a>
</h2><p></p>
<p>I'm trying to write a script the simplifies the execution of a program: 
 
After starting the program (sh ~/.mfix/model/make_mfix) I am prompted four times for options: 
Do you need SMP version? (y/n) 
Do you need DMP version? (y/n) 
Do you need debug version? (y/n) 
Force re-compilation of... (2 Replies)</p>
<p></p><h5>Discussion started by: lanew</h5><p></p>
</div>
<div>
<p></p><h2>7. UNIX for Dummies Questions &amp; Answers</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/unix-for-dummies-questions-and-answers/181665-bash-script-execute-program-rename-files.html?s=1aa398b618623ab68a008d5fc8b369b0">Bash script to execute a program to rename files</a>
</h2><p></p>
<p>I just can't figure it out , so please just give me a pice of advise how to: 
 
The existing Linux program foo2bar takes as its only argument the name of a single foo file and converts it to an appropriately-named bar file. Provide a script that when executed will run foo2bar against all foo... (4 Replies)</p>
<p></p><h5>Discussion started by: raymen</h5><p></p>
</div>
<div>
<p></p><h2>8. Shell Programming and Scripting</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/shell-programming-and-scripting/164772-bash-script-check-if-program-running.html?s=1aa398b618623ab68a008d5fc8b369b0">bash script to check if a program is running</a>
</h2><p></p>
<p>I'm a bit new to bash programming and I was assigned the job of writing a script that will check to see if a program server is running and to restart the program if it is not up. The script is supposed to check the program every hour (which I have looked up and I believe I know how to do) and send... (3 Replies)</p>
<p></p><h5>Discussion started by: mcknz</h5><p></p>
</div>
<div>
<p></p><h2>9. Shell Programming and Scripting</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/shell-programming-and-scripting/164854-problem-bash-shell-script-program.html?s=1aa398b618623ab68a008d5fc8b369b0">Problem with bash shell script program</a>
</h2><p></p>
<p>Hi, 
 
This is my program. 
 
#!/bin/bash 
today=`date +"%b-%d-%Y"` 
SERVICE="pbxconnect.php" 
if ; then 
 echo "pbx program is running" 
else 
 nohup php pbxconnect.php &gt; logpbx-$today.txt &amp; 
fi 
 
On executing using "sh myprogram.sh" , i get the following error. 
myprogram.sh: line 4: ' 
 
My... (7 Replies)</p>
<p></p><h5>Discussion started by: gskumar1234</h5><p></p>
</div>
<div>
<p></p><h2>10. Homework &amp; Coursework Questions</h2>
<p></p>
<p>
</p><h2> <a href="https://www.unix.com/homework-and-coursework-questions/152959-run-program-bash-cgi-script.html?s=1aa398b618623ab68a008d5fc8b369b0">Run Program from Bash CGI-Script</a>
</h2><p></p>
<p>Use and complete the template provided. The entire template must be completed. If you don't, your post may be deleted! 
 
1. The problem statement, all variables and given/known data: 
This is a problem I am having with my 2 semester senior project. I have a LAMP server running Ubuntu 9.10 with... (8 Replies)</p>
<p></p><h5>Discussion started by: JMooney5115</h5><p></p>
</div>
 </div>||||I|||| The UNIX and Linux Forums
 

 Forum Home
 Linux and Unix Man Pages
 Search Forums
 Search Community Posts
 Today's Posts
 Quick Links
 
 
 
 
 
 
 
 
 
 
 Login or Register to Ask a Question and Join Our Community

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


 Programming

 Putting bash script in C program

 Tags 
 programming
 


 Login to Discuss or Reply to this Discussion in Our Community
  
  
 Page 1 of 3 1 2 3 > 
  
  
  
 

 Thread Tools Search this Thread
 

 Top Forums Programming Putting bash script in C program

 # 1
 02-17-2013
 SkySmart
 Registered User
 919, 3
 Join Date: Dec 2006
 Last Activity: 5 March 2020, 5:37 PM EST
 Posts: 919
 Thanks Given: 757
 Thanked 3 Times in 3 Posts
 Putting bash script in C program
 suppose i have a bash script:

 Code:

 #!/bin/bash
 
 echo "hello"
 echo "how are you"
 echo "today"


 how can i put the entire script above into a basic c program?

 i do not want to translate the bash code to a c code. i want C to run the bash code. is this possible?

 i found this on the internet but i'm not sure i understand it:



 Code:

 #include <stdio.h>
 #include <stdlib.h>
 
 #define SHELLSCRIPT "\
 for ((i=0 ; i < 10 ; i++))\n\
 do\n\
 echo \"Count: $i\"\n\
 done\n\
 "
 
 int main()
 {
 puts("Will execute sh with the following script :");
 puts(SHELLSCRIPT);
 puts("Starting now:");
 system(SHELLSCRIPT);
 return 0;
 }


 i'm looking for a C program where i can just insert the bash code into it and have it run. something like this:


 Code:

 #include <stdio.h>
 #include <stdlib.h>
 
 int main()
 {
 puts("Will execute sh with the following script :");
 puts(#!/bin/bash
 echo "hello"
 echo "how are you"
 echo "today");
 puts("Starting now:");
 system(SHELLSCRIPT);
 return 0;
 }


 SkySmart 
 View Public Profile for SkySmart
 Find all posts by SkySmart 
 
 

 # 2
 02-17-2013
 Yoda
 Moderator
 3,689, 1,352
 Join Date: Jan 2012
 Last Activity: 22 August 2020, 11:29 PM EDT
 Location: Galactic Empire
 Posts: 3,689
 Thanks Given: 268
 Thanked 1,352 Times in 1,258 Posts

 Code:

 #include <stdio.h>
 #include <stdlib.h>
 
 #define SHELLSCRIPT "\
 #/bin/bash \n\
 echo \"hello\" \n\
 echo \"how are you\" \n\
 echo \"today\" \n\
 "
 
 int main()
 {
 puts("Will execute sh with the following script :");
 puts(SHELLSCRIPT);
 puts("Starting now:");
 system(SHELLSCRIPT);
 return 0;
 }


 The #define SHELLSCRIPT directive is used in C to define a named constant: SHELLSCRIPT which contains the shell script.

 The back slash \ at the end of each line is used to type the code in next line for better readability.

 The new line \n is used to put the code in next line.

 Double quotes " within the shell script has to be escaped \" to distinguish it between the original opening and closing double quotes of constant value.

 Finally the system function is called by passing the named constant: SHELLSCRIPT as argument which contains the shell script.

 I hope it makes sense now.

 This User Gave Thanks to Yoda For This Post:
 SkySmart

 Yoda 
 View Public Profile for Yoda
 Visit Yoda's homepage! 
 Find all posts by Yoda 
 
 

 # 3
 02-17-2013
 SkySmart
 Registered User
 919, 3
 Join Date: Dec 2006
 Last Activity: 5 March 2020, 5:37 PM EST
 Posts: 919
 Thanks Given: 757
 Thanked 3 Times in 3 Posts


 Quote:


 Originally Posted by bipinajith


 Code:

 #include <stdio.h>
 #include <stdlib.h>
 
 #define SHELLSCRIPT "\
 #/bin/bash \n\
 echo \"hello\" \n\
 echo \"how are you\" \n\
 echo \"today\" \n\
 "
 
 int main()
 {
 puts("Will execute sh with the following script :");
 puts(SHELLSCRIPT);
 puts("Starting now:");
 system(SHELLSCRIPT);
 return 0;
 }


 The #define SHELLSCRIPT directive is used in C to define a named constant: SHELLSCRIPT which contains the shell script.

 The back slash \ at the end of each line is used to type the code in next line for better readability.

 The new line \n is used to put the code in next line.

 Double quotes " within the shell script has to be escaped \" to distinguish it between the original opening and closing double quotes of constant value.

 Finally the system function is called by passing the named constant: SHELLSCRIPT as argument which contains the shell script.

 I hope it makes sense now.


 thank you soo much. you are a godsend. thank you.

 i'm curious though, and please forgive my newbie status to c++, but can you please tell me how do i run this program? i like to keep things simple.

 so if i named your script to mycplus, can i run it from the command line like this:


 Code:

 #mycplus


 can a C program that contains a bash script like the one above be compiled and made into an executable?

 how would you compile it?

 thanks again!!!

 SkySmart 
 View Public Profile for SkySmart
 Find all posts by SkySmart 
 
 

 # 4
 02-17-2013
 Yoda
 Moderator
 3,689, 1,352
 Join Date: Jan 2012
 Last Activity: 22 August 2020, 11:29 PM EDT
 Location: Galactic Empire
 Posts: 3,689
 Thanks Given: 268
 Thanked 1,352 Times in 1,258 Posts
 First of all this is a C Program. Below are the steps to compile:

 1. Create a C program file:

 Code:

 $ cat > cprog.c
 #include <stdio.h>
 #include <stdlib.h>
 
 #define SHELLSCRIPT "\
 #/bin/bash \n\
 echo \"hello\" \n\
 echo \"how are you\" \n\
 echo \"today\" \n\
 "
 
 int main()
 {
 puts("Will execute sh with the following script :");
 puts(SHELLSCRIPT);
 puts("Starting now:");
 system(SHELLSCRIPT);
 return 0;
 }


 2. Compile the C program file using cc compiler:

 Code:

 $ cc cprog.c


 3. Compiler will compile & link and create an output file: a.out which you can run to see the result:

 Code:

 $ ./a.out


 If you want to create an output file with a name of your choice, use -o option:

 Code:

 $ cc cprog.c -o cprog


 Run the compiled & linked output file created: cprog 

 Code:

 $ ./cprog


 This User Gave Thanks to Yoda For This Post:
 SkySmart

 Yoda 
 View Public Profile for Yoda
 Visit Yoda's homepage! 
 Find all posts by Yoda 
 
 

 # 5
 02-17-2013
 SkySmart
 Registered User
 919, 3
 Join Date: Dec 2006
 Last Activity: 5 March 2020, 5:37 PM EST
 Posts: 919
 Thanks Given: 757
 Thanked 3 Times in 3 Posts
 thanks again. one last question.

 the bash script i intend on embedding into this C program will be accepting several arguments from the command line. and it is a very big bash script. will C be able to catch the arguments?

 meaning, after i have embedded the bash script into C, i will be running the C program from the command line like this:


 Code:

 ./cprog arg1 arg2 arg3 arg4 arg5 'arg6' 'arg7' arg8 arg9 arg10



 the arguments are meant for the bash script. will C be able to pass it to the script?

 if i was running the bash script alone without it being embedded into C, the bash script will accept and use the arguments just fine. but i just want to make sure when it is embedded in C there wont be problems.

 thanks again.

 SkySmart 
 View Public Profile for SkySmart
 Find all posts by SkySmart 
 
 

 # 6
 02-17-2013
 Yoda
 Moderator
 3,689, 1,352
 Join Date: Jan 2012
 Last Activity: 22 August 2020, 11:29 PM EDT
 Location: Galactic Empire
 Posts: 3,689
 Thanks Given: 268
 Thanked 1,352 Times in 1,258 Posts
 No, that will not work. To make things simple I would suggest to write the bash script in a separate file and call it from C program by passing the required arguments:

 Code:

 #include <stdio.h>
 #include <stdlib.h>
 
 int main()
 {
 puts("Starting now:");
 system("/path_to_script/script_name arg1 arg2 arg3");
 return 0;
 }


 This way it will be easy to maintain.

 Yoda 
 View Public Profile for Yoda
 Visit Yoda's homepage! 
 Find all posts by Yoda 
 
 

 # 7
 02-17-2013
 SkySmart
 Registered User
 919, 3
 Join Date: Dec 2006
 Last Activity: 5 March 2020, 5:37 PM EST
 Posts: 919
 Thanks Given: 757
 Thanked 3 Times in 3 Posts


 Quote:


 Originally Posted by bipinajith


 No, that will not work. To make things simple I would suggest to write the bash script in a separate file and call it from C program by passing the required arguments:

 Code:

 #include <stdio.h>
 #include <stdlib.h>
 
 int main()
 {
 puts("Starting now:");
 system("/path_to_script/script_name arg1 arg2 arg3");
 return 0;
 }


 This way it will be easy to maintain.


 that was my first option. but the whole goal here was to conceal the bash code. so i figure if i can embed it into C, i'll be able to hide the code. but if C is calling the script, the script will be open for everyone to read.

 as i was typing this, something else occurred to me. i'm thinking, i can encode the script using a password. tell C to decode the script using the password i put in the C code. and then C can call the script after script has been decoded.

 dont know if that makes sense.

 SkySmart 
 View Public Profile for SkySmart
 Find all posts by SkySmart 
 
 

 Page 1 of 3 1 2 3 > 
 
 
 
 

 Login or Register to Ask a Question


 Previous Thread | Next Thread


 10 More Discussions You Might Find Interesting

 1. UNIX for Beginners Questions & Answers

 Pass RegEx to java program in bash script

 I can't seem to get this right. I've tried it every way imaginable using every trick I see on stackexchange and such. No luck. So nothing major here, something like: #!/bin/bash SEARCH="ARG1 ARG2 '((^EXACT$)|(.*InTheMiddle*)|(^AtBeginning*))'" java -cp /my/class/path MyClassName $SEARCH... (3 Replies)

 Discussion started by: stonkers

 3 Replies

 2. Programming

 Program or bash script to see total progress of copy

 hi all, i want a program or to make a bash script to find out the total ETA/percent (would be nice aswell a progress bar) of a copy recursive command so lets say i do - cp -r /source_folder/ /destinatation_folder/ and when i run it i get no information on the screen of how the copy is... (20 Replies)

 Discussion started by: robertkwild

 20 Replies

 3. Shell Programming and Scripting

 Help with Bash Shell Script Spell Checker program.

 I have a majority of this problem done but seem to be struggling on the last couple of steps. Here is the whole problem to help you guys get a better understanding. Write a shell script that implements a simple spell checker. The filename you will use for your script will be your Z-id followed... (1 Reply)

 Discussion started by: DsmRacer2k14

 1 Replies

 4. UNIX for Dummies Questions & Answers

 Running a C/C++ program and/or bash script from a server

 I wish to be able to give to a client the opportunity to : 0) Turn one of my ubuntu computers into a webserver 1) See a webpage after visiting a url where an external user/client can set a couple of variables (e.g. Number1= ?, Number2=?) 2) By pressing "run" the program runs on my machine 3)... (1 Reply)

 Discussion started by: frad

 1 Replies

 5. Shell Programming and Scripting

 Putting a separator in file using awk/bash

 I have a file with the following content: a-123-345-232 a-23343-4545-545 a-67676-45454-8787 a-129-8912-9824 b-564-78678-2322 b-5454-76767-8899 b-85554-124-152-29 c-34534-654543-323 (... and so on, actually these are pretty huge records) Now, I want that the file should not be broken in to... (8 Replies)

 Discussion started by: askerbis

 8 Replies

 6. Shell Programming and Scripting

 Bash script to start program and answer prompts?

 I'm trying to write a script the simplifies the execution of a program: After starting the program (sh ~/.mfix/model/make_mfix) I am prompted four times for options: Do you need SMP version? (y/n) Do you need DMP version? (y/n) Do you need debug version? (y/n) Force re-compilation of... (2 Replies)

 Discussion started by: lanew

 2 Replies

 7. UNIX for Dummies Questions & Answers

 Bash script to execute a program to rename files

 I just can't figure it out , so please just give me a pice of advise how to: The existing Linux program foo2bar takes as its only argument the name of a single foo file and converts it to an appropriately-named bar file. Provide a script that when executed will run foo2bar against all foo... (4 Replies)

 Discussion started by: raymen

 4 Replies

 8. Shell Programming and Scripting

 bash script to check if a program is running

 I'm a bit new to bash programming and I was assigned the job of writing a script that will check to see if a program server is running and to restart the program if it is not up. The script is supposed to check the program every hour (which I have looked up and I believe I know how to do) and send... (3 Replies)

 Discussion started by: mcknz

 3 Replies

 9. Shell Programming and Scripting

 Problem with bash shell script program

 Hi, This is my program. #!/bin/bash today=`date +"%b-%d-%Y"` SERVICE="pbxconnect.php" if ; then echo "pbx program is running" else nohup php pbxconnect.php > logpbx-$today.txt & fi On executing using "sh myprogram.sh" , i get the following error. myprogram.sh: line 4: ' My... (7 Replies)

 Discussion started by: gskumar1234

 7 Replies

 10. Homework & Coursework Questions

 Run Program from Bash CGI-Script

 Use and complete the template provided. The entire template must be completed. If you don't, your post may be deleted! 1. The problem statement, all variables and given/known data: This is a problem I am having with my 2 semester senior project. I have a LAMP server running Ubuntu 9.10 with... (8 Replies)

 Discussion started by: JMooney5115

 8 Replies

 
 
 

 Login or Register to Ask a Question

 Member Badges and Information Modal

 ×
 Close


 Featured Tech Videos


 All times are GMT -4. The time now is 03:34 PM .

 Contact Us - The UNIX and Linux Forums - unix commands, linux commands, linux server, linux ubuntu, shell script, linux distros. - Advertising - Top
 Unix & Linux Forums Content Copyright 1993-2022. All Rights Reserved.
 Privacy Policy

10 More Discussions You Might Find Interesting
 
  1. UNIX for Beginners Questions &amp; Answers
 
  Pass RegEx to java program in bash script
  
I can't seem to get this right. I've tried it every way imaginable using every trick I see on stackexchange and such. No luck. So nothing major here, something like: 
 
 
#!/bin/bash 
 
SEARCH="ARG1 ARG2 '((^EXACT$)|(.*InTheMiddle*)|(^AtBeginning*))'" 
java -cp /my/class/path MyClassName $SEARCH... (3 Replies)
  Discussion started by: stonkers  
  2. Programming
 
  Program or bash script to see total progress of copy
  
hi all, 
 
i want a program or to make a bash script to find out the total ETA/percent (would be nice aswell a progress bar) of a copy recursive command 
 
so lets say i do - 
 
cp -r /source_folder/ /destinatation_folder/ 
 
and when i run it i get no information on the screen of how the copy is... (20 Replies)
  Discussion started by: robertkwild  
  3. Shell Programming and Scripting
 
  Help with Bash Shell Script Spell Checker program.
  
I have a majority of this problem done but seem to be struggling on the last couple of steps. Here is the whole problem to help you guys get a better understanding. 
 
Write a shell script that implements a simple spell checker. 
The filename you will use for your script will be your Z-id followed... (1 Reply)
  Discussion started by: DsmRacer2k14  
  4. UNIX for Dummies Questions &amp; Answers
 
  Running a C/C++ program and/or bash script from a server
  
I wish to be able to give to a client the opportunity to : 
 
0) Turn one of my ubuntu computers into a webserver 
1) See a webpage after visiting a url where an external user/client can set a couple of variables (e.g. Number1= ?, Number2=?) 
2) By pressing "run" the program runs on my machine 
3)... (1 Reply)
  Discussion started by: frad  
  5. Shell Programming and Scripting
 
  Putting a separator in file using awk/bash
  
I have a file with the following content: 
a-123-345-232 
a-23343-4545-545 
a-67676-45454-8787 
a-129-8912-9824 
b-564-78678-2322 
b-5454-76767-8899 
b-85554-124-152-29 
c-34534-654543-323 
(... and so on, actually these are pretty huge records) 
Now, I want that the file should not be broken in to... (8 Replies)
  Discussion started by: askerbis  
  6. Shell Programming and Scripting
 
  Bash script to start program and answer prompts?
  
I'm trying to write a script the simplifies the execution of a program: 
 
After starting the program (sh ~/.mfix/model/make_mfix) I am prompted four times for options: 
Do you need SMP version? (y/n) 
Do you need DMP version? (y/n) 
Do you need debug version? (y/n) 
Force re-compilation of... (2 Replies)
  Discussion started by: lanew  
  7. UNIX for Dummies Questions &amp; Answers
 
  Bash script to execute a program to rename files
  
I just can't figure it out , so please just give me a pice of advise how to: 
 
The existing Linux program foo2bar takes as its only argument the name of a single foo file and converts it to an appropriately-named bar file. Provide a script that when executed will run foo2bar against all foo... (4 Replies)
  Discussion started by: raymen  
  8. Shell Programming and Scripting
 
  bash script to check if a program is running
  
I'm a bit new to bash programming and I was assigned the job of writing a script that will check to see if a program server is running and to restart the program if it is not up. The script is supposed to check the program every hour (which I have looked up and I believe I know how to do) and send... (3 Replies)
  Discussion started by: mcknz  
  9. Shell Programming and Scripting
 
  Problem with bash shell script program
  
Hi, 
 
This is my program. 
 
#!/bin/bash 
today=`date +"%b-%d-%Y"` 
SERVICE="pbxconnect.php" 
if ; then 
 echo "pbx program is running" 
else 
 nohup php pbxconnect.php &gt; logpbx-$today.txt &amp; 
fi 
 
On executing using "sh myprogram.sh" , i get the following error. 
myprogram.sh: line 4: ' 
 
My... (7 Replies)
  Discussion started by: gskumar1234  
  10. Homework &amp; Coursework Questions
 
  Run Program from Bash CGI-Script
  
Use and complete the template provided. The entire template must be completed. If you don't, your post may be deleted! 
 
1. The problem statement, all variables and given/known data: 
This is a problem I am having with my 2 semester senior project. I have a LAMP server running Ubuntu 9.10 with... (8 Replies)
  Discussion started by: JMooney5115
Putting bash script in C program
https://www.unix.com/programming/216190-putting-bash-script-c-program.html
https://codegolf.stackexchange.com/questions/tagged/bash
Newest 'bash' Questions
2023-02-23
None
<div><div>
 
 <div>
 <p>
 </p><h2>
Questions tagged [bash] </h2>
 <p></p>
 
 </div>
 <div>
 <p>
This challenge is related to the Bash (Bourne Again SHell) language. Note that challenges that require the answers to be in a specific language are generally discouraged. </p>
 <div>
 <ul>
 <li>
 <a href="/tags/bash/info">Learn more…</a>
 </li>
 <li>
 <a href="/tags/bash/topusers">Top users</a>
 </li>
 <li>
 <a href="/tags/bash/synonyms">Synonyms</a>
 </li>
 </ul>
 </div>
 </div>
 
 <div>
 
<div>
 <div>
 
 <p>9
 votes
 </p>
 <p>4
 answers
 </p>
 <p>436
 views
 </p>
 </div>
 <div>
 <h3>
 <a href="/questions/258174/shortest-way-to-convert-the-result-of-a-test-to-a-string-output-e-g-true-or-fa">Shortest way to convert the result of a test to a string output (e.g. true or false) in bash</a>
 </h3>
 <p>
 I'm trying to shorten a bash solution to a Code Golf challenge, which requires an output of true or false. I've managed to ...
 </p>
 <div>
 <div>
 <a href="/users/70305/shadowranger"> <p>
 </p>
</a>
 </div>
 <div>
 
 
 <ul>
 <li>442</li>
 </ul>
 
 </div>
 <p><time>asked Feb 23 at 16:02</time>
</p></div>
 </div>
</div>
 
<div>
 <div>
 
 <p>-4
 votes
 </p>
 <p>4
 answers
 </p>
 <p>274
 views
 </p>
 </div>
 <div>
 <h3>
 <a href="/questions/137681/tail-troll-file-truncated">tail: troll: file truncated</a>
 </h3>
 <p>
 Background
When you run tail -f file in bash, the file is outputted and then any subsequent appends.
However, when you remove something that has already been ...
 </p>
 <div>
 <p> <p>
 </p>
 </p>
 
 <p><time>asked Aug 4, 2017 at 23:13</time>
</p></div>
 </div>
</div>
 
<div>
 <div>
 
 <p>7
 votes
 </p>
 <p>1
 answer
 </p>
 <p>559
 views
 </p>
 </div>
 <div>
 <h3>
 <a href="/questions/130149/code-golfing-split-string-in-bash">Code Golfing Split String in Bash [closed]</a>
 </h3>
 <p>
 Let us play a little golfing game. 
Given a single line of N space separated numbers from STDIN, one must output those numbers on N lines. 
So far, I came up with the three following bash solutions :
...
 </p>
 <div>
 <div>
 <a href="/users/71912/brett"> <p>
 </p>
</a>
 </div>
 <div>
 
 
 <ul>
 <li>79</li>
 </ul>
 
 </div>
 <p><time>asked Jul 6, 2017 at 13:04</time>
</p></div>
 </div>
</div>
 
<div>
 <h3>
 <a href="/questions/73162/shorter-way-to-assign-a-default-value-to-the-standard-output-stream">Shorter way to assign a default value to the standard output stream</a>
 </h3>
 <p>
 I have this code :
tr ' ' '\n'|sort -n|head -1
The code is pretty simple, it takes a list of integer in the standard input stream (like ...
 </p>
 <div>
 <div>
 <a href="/users/46691/magus"> <p>
 </p>
</a>
 </div>
 <div>
 
 
 <ul>
 <li>153</li>
 </ul>
 
 </div>
 <p><time>asked Feb 15, 2016 at 12:18</time>
</p></div>
 </div>
 
<div>
 <h3>
 <a href="/questions/57572/write-a-panic-script-to-remote-secure-a-mac-pro-from-an-untrustworthy-local-user">Write a panic script to remote secure a Mac Pro from an untrustworthy local user [closed]</a>
 </h3>
 <p>
 The Situation
Suppose I allow "Shady Sam" admin access on my workstation to perform an important administrative task on my Mac Pro for me by giving them a temporary root login password. (Assume they ...
 </p>
 <div>
 <div>
 <a href="/users/43081/jvriesem"> <p>
 </p>
</a>
 </div>
 <div>
 
 
 <ul>
 <li>299</li>
 </ul>
 
 </div>
 <p><time>asked Sep 11, 2015 at 0:47</time>
</p></div>
 </div>
 
<div>
 <div>
 
 <p>69
 votes
 </p>
 <p>42
 answers
 </p>
 <p>11k
 views
 </p>
 </div>
 <div>
 <h3>
 <a href="/questions/15279/tips-for-golfing-in-bash">Tips for golfing in Bash</a>
 </h3>
 <p>
 What general tips do you have for golfing in Bash? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Bash (e.g. "remove comments" is not ...
 </p>
 <div>
 <div>
 <a href="/users/4198/manatwork"> <p>
 </p>
</a>
 </div>
 <div>
 
 
 <ul>
 <li>19.8k</li>
 </ul>
 
 </div>
 <p><time>asked Nov 15, 2013 at 9:14</time>
</p></div>
 </div>
</div>
 </div>
 <br />
 </div>||||I|||| Stack Exchange Network

 Stack Exchange network consists of 181 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.

 Visit Stack Exchange
 Loading…
 1. 
 + Tour Start here for a quick overview of the site
 + Help Center Detailed answers to any questions you might have
 + Meta Discuss the workings and policies of this site
 + About Us Learn more about Stack Overflow the company, and our products.
 2. 

 3. current community

 + Code Golf
 help chat
 + Code Golf Meta

 your communities

 Sign up or log in to customize your list.

 more stack exchange communities

 company blog
 4. 
 5. Log in
 6. Sign up
 1. Home
 2. 
 1. Public
 2. Questions
 3. Tags
 4. Users
 5. Companies
 6. Unanswered
 3. 
 1. Teams
 Stack Overflow for Teams – Start collaborating and sharing organizational knowledge. Create a free Team Why Teams?
 2. Teams
 3. Create free Team

 Teams

 Q&A for work

 Connect and share knowledge within a single location that is structured and easy to search.

 Learn more about Teams

 Questions tagged [bash]

 Ask Question

 This challenge is related to the Bash (Bourne Again SHell) language. Note that challenges that require the answers to be in a specific language are generally discouraged.

 * Learn more…
 * Top users
 * Synonyms
 6 questions
 Newest
 Active
 Bountied
 Unanswered
 More
 * Bountied 0
 * Unanswered
 * Frequent
 * Score
 * 
 * Unanswered (my tags)
 Filter
 Filter by
 No answers
 No accepted answer
 Has bounty
 Sorted by
 Newest
 Recent activity
 Highest score
 Most frequent
 Bounty ending soon
 Tagged with
 My watched tags
 The following tags:
 Apply filter
 Cancel
 9 votes
 4 answers
 436 views

 Shortest way to convert the result of a test to a string output (e.g. true or false) in bash

 I'm trying to shorten a bash solution to a Code Golf challenge, which requires an output of true or false . I've managed to ...
 * tips
 * bash
 ShadowRanger
 * 442
 asked Feb 23 at 16:02
 -4 votes
 4 answers
 274 views

 tail: troll: file truncated

 Background When you run tail -f file in bash, the file is outputted and then any subsequent appends. However, when you remove something that has already been ...
 * code-golf
 * string
 * file-system
 * bash
 user58826
 asked Aug 4, 2017 at 23:13
 7 votes
 1 answer
 559 views

 Code Golfing Split String in Bash [closed]

 Let us play a little golfing game. Given a single line of N space separated numbers from STDIN, one must output those numbers on N lines. So far, I came up with the three following bash solutions : ...
 * code-golf
 * tips
 * bash
 Brett
 * 79
 asked Jul 6, 2017 at 13:04
 5 votes
 4 answers
 497 views

 Shorter way to assign a default value to the standard output stream

 I have this code : tr ' ' '\n'|sort -n|head -1 The code is pretty simple, it takes a list of integer in the standard input stream (like ...
 * code-golf
 * tips
 * bash
 Magus
 * 153
 asked Feb 15, 2016 at 12:18
 12 votes
 1 answer
 575 views

 Write a panic script to remote secure a Mac Pro from an untrustworthy local user [closed]

 The Situation Suppose I allow "Shady Sam" admin access on my workstation to perform an important administrative task on my Mac Pro for me by giving them a temporary root login password. (Assume they ...
 * popularity-contest
 * python
 * bash
 jvriesem
 * 299
 asked Sep 11, 2015 at 0:47
 69 votes
 42 answers
 11k views

 Tips for golfing in Bash

 What general tips do you have for golfing in Bash? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Bash (e.g. "remove comments" is not ...
 * code-golf
 * tips
 * bash
 manatwork
 * 19.8k
 asked Nov 15, 2013 at 9:14

 Welcome to Code Golf and Coding Challenges Stack Exchange! This is a site for recreational programming competitions, not general programming questions. Challenges must have an objective scoring criterion, and it is highly recommended to first post proposed challenges in the Sandbox.
 * The Overflow Blog
 * ML and AI consulting-as-a-service (Ep. 541)
 * Why governments need open source more than ever
 * Featured on Meta
 * Ticket smash for [status-review] tag: Part Deux
 * We've added a "Necessary cookies only" option to the cookie consent popup
 * 2022: a year in moderation
 * Best of CGCC 2023 - Now Accepting Nominations!

 Related Tags

 code-golf × 4
 tips × 4
 file-system × 1
 popularity-contest × 1
 string × 1
 python × 1

 Hot Network Questions

 * Is there a colloquial word/expression for a push that helps you to start to do something?
 * Will floating pantry shelves built with 2x2s be ok?
 * How do gas turbine engines and turbofan engines keep constant compressor side rpm?
 * Discrete N-channel-MOSFET driver switching circuit with NPN and PNP transistor
 * Why was intuitionist logic abandoned?
 * Dilation of bounded linear operators
 * Why pressing enter increases the file size by 2 bytes in windows
 * In Romans 8:18, how is the aorist ἀποκαλυφθῆναι translated as a future tense?
 * Why is the Delta IV Heavy taller than the Delta IV Medium?
 * Definite integrals with equal limits
 * Why do heating curves have plateaus?
 * Can a VGA monitor be connected to parallel port?
 * What is the circuit symbol for a triple gang potentiometer?
 * When is the multiplication map of the algebraic tensor product of C*-algebras injective?
 * Where to put an inheritance of $1.4 million upon first receiving it
 * "Expect" Nature publication for PhD?
 * How to create scales on an dragon egg?
 * Why is np.dot so much faster than np.sum?
 * How can we denote objects that no longer exist?
 * article usage, He invented THE slide rule
 * How does the Chinese government having minority stakes and board seats gives it effective control over them?
 * Designing a Python string validation library
 * Is the "Chinese room" an explanation of how ChatGPT works?
 * My supervisor is suggesting implementing an idea that they previously rejected
 more hot questions
 Newest bash questions feed

 Subscribe to RSS

 Newest bash questions feed

 To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

 Code Golf

 * Tour
 * Help
 * Chat
 * Contact
 * Feedback

 Company

 * Stack Overflow
 * Teams
 * Advertising
 * Collectives
 * Talent
 * About
 * Press
 * Legal
 * Privacy Policy
 * Terms of Service
 * Cookie Settings
 * Cookie Policy

 Stack Exchange Network

 * Technology
 * Culture & recreation
 * Life & arts
 * Science
 * Professional
 * Business
 * API
 * Data
 * Blog
 * Facebook
 * Twitter
 * LinkedIn
 * Instagram

 Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA. rev 2023.2.24.43259

 Your privacy

 By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

 Accept all cookies Necessary cookies only
 Customize settings
Questions tagged [bash] 
  
 
 
 
 
This challenge is related to the Bash (Bourne Again SHell) language. Note that challenges that require the answers to be in a specific language are generally discouraged. 
 
 
 
 Learn more…
 
 
 Top users
 
 
 Synonyms
 
 
 
 
 
 
 
 
 
 9
 votes
 
 4
 answers
 
 436
 views
 
 
 
 
 Shortest way to convert the result of a test to a string output (e.g. true or false) in bash
 
 
 I'm trying to shorten a bash solution to a Code Golf challenge, which requires an output of true or false. I've managed to ...
 
 
 
  
 
 
 
 
 
 
 442
 
 
 
  asked Feb 23 at 16:02
 
 
 
 
 
 -4
 votes
 
 4
 answers
 
 274
 views
 
 
 
 
 tail: troll: file truncated
 
 
 Background
When you run tail -f file in bash, the file is outputted and then any subsequent appends.
However, when you remove something that has already been ...
 
 
  
 
 
 
  asked Aug 4, 2017 at 23:13
 
 
 
 
 
 7
 votes
 
 1
 answer
 
 559
 views
 
 
 
 
 Code Golfing Split String in Bash [closed]
 
 
 Let us play a little golfing game. 
Given a single line of N space separated numbers from STDIN, one must output those numbers on N lines. 
So far, I came up with the three following bash solutions :
...
 
 
 
  
 
 
 
 
 
 
 79
 
 
 
  asked Jul 6, 2017 at 13:04
 
 
 
 
 Shorter way to assign a default value to the standard output stream
 
 
 I have this code :
tr ' ' '\n'|sort -n|head -1
The code is pretty simple, it takes a list of integer in the standard input stream (like ...
 
 
 
  
 
 
 
 
 
 
 153
 
 
 
  asked Feb 15, 2016 at 12:18
 
 
 
 
 Write a panic script to remote secure a Mac Pro from an untrustworthy local user [closed]
 
 
 The Situation
Suppose I allow "Shady Sam" admin access on my workstation to perform an important administrative task on my Mac Pro for me by giving them a temporary root login password. (Assume they ...
 
 
 
  
 
 
 
 
 
 
 299
 
 
 
  asked Sep 11, 2015 at 0:47
 
 
 
 
 
 69
 votes
 
 42
 answers
 
 11k
 views
 
 
 
 
 Tips for golfing in Bash
 
 
 What general tips do you have for golfing in Bash? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Bash (e.g. "remove comments" is not ...
 
 
 
  
 
 
 
 
 
 
 19.8k
 
 
 
  asked Nov 15, 2013 at 9:14
Newest 'bash' Questions
https://codegolf.stackexchange.com/questions/tagged/bash
https://developerinsider.co/compile-c-program-with-gcc-compiler-on-bash-on-ubuntu-on-windows-10/
Compile C program with gcc compiler on Bash on Ubuntu on Windows 10
2016-11-19
Vineet Choudhary
<div><div><p>The GNU Compiler Collection (GCC) is a compiler system produced by the GNU Project supporting various programming languages. You can compile a C program by using the gcc command in Windows 10 Bash on Ubuntu.</p>
<p>If you don't have a enable Ubuntu on Windows check out <a href="https://developerinsider.co/stepwise-guide-to-enable-windows-10-subsystem-for-linux/">Stepwise Guide to Enable Windows 10’s Ubuntu Bash Shell (Windows Subsystem for Linux).</a></p>
<h2>2. Install gcc compiler in Windows 10 Bash</h2>
<p>To install <code>gcc</code> compiler in Windows 10 Bash, Open bash and run this command</p>
<pre><code>apt-get install gcc
</code></pre>
<p></p>
<p>Make sure compiler is installed on your Windows 10 Bash. Type the following command to verify that gcc is installed:</p>
<pre><code>which gcc
</code></pre>
<p><strong>Sample outputs:</strong></p>
<pre><code>/usr/bin/gcc
</code></pre>
<p>Find out version of gcc, run:</p>
<pre><code>gcc --version
</code></pre>
<p></p>
<h2>3. Write your first program on bash</h2>
<p>Use a text editor such as nano or vi to create a C program called hello.c:</p>
<pre><code>nano hello.c
</code></pre>
<p></p>
<p>Type the following lines (program):</p>
<pre><code>#include &lt;stdio.h&gt;
int main()
{
 printf("hello world\n");
 return 0;
}
</code></pre>
<p></p>
<p>After writing your program, press <code>Ctrl + O</code> and hit <code>Enter</code> key to save your program. To exit nano press <code>Ctrl + X</code>.</p>
<h2>4. Compile and Run Program</h2>
<p>To compile C program <code>hello.c</code>, and create an executable file called hello, enter:</p>
<pre><code>gcc hello.c -o hello
</code></pre>
<p>To execute program first, enter:</p>
<pre><code>./hello
</code></pre>
<p><strong>Output:</strong></p>
<pre><code>hello world
</code></pre>
<p></p>
</div>||||I|||| * C
 * C++
 * iOS
 * .NET
 * Android
 * Wiki
 * Interview
 * Tech
 * Tips
 * Downloads
 * About
 * Follow

 Subscribe to Developer Insider

 Get the latest posts delivered right to your inbox
 Subscribe
 Great! Check your inbox and click the link to confirm your subscription
 Please enter a valid email address!
 * 
 * 
 * C
 * C++
 * iOS
 * .NET
 * Android
 * Wiki
 * Interview
 * Tech
 * Tips
 * Downloads
 * About

 Compile C program with gcc compiler on Bash on Ubuntu on Windows 10

 2 min read
 By Vineet Choudhary

 The GNU Compiler Collection (GCC) is a compiler system produced by the GNU Project supporting various programming languages. You can compile a C program by using the gcc command in Windows 10 Bash on Ubuntu.

 1.Enable Bash on Ubuntu on Windows 10

 If you don't have a enable Ubuntu on Windows check out Stepwise Guide to Enable Windows 10’s Ubuntu Bash Shell (Windows Subsystem for Linux).

 2. Install gcc compiler in Windows 10 Bash

 To install gcc compiler in Windows 10 Bash, Open bash and run this command

 apt-get install gcc
 

 Make sure compiler is installed on your Windows 10 Bash. Type the following command to verify that gcc is installed:

 which gcc
 

 Sample outputs:

 /usr/bin/gcc
 

 Find out version of gcc, run:

 gcc --version
 

 3. Write your first program on bash

 Use a text editor such as nano or vi to create a C program called hello.c:

 nano hello.c
 

 Type the following lines (program):

 #include <stdio.h>
 
 int main()
 {
 printf("hello world\n");
 return 0;
 }
 

 After writing your program, press Ctrl + O and hit Enter key to save your program. To exit nano press Ctrl + X.

 4. Compile and Run Program

 To compile C program hello.c, and create an executable file called hello, enter:

 gcc hello.c -o hello
 

 To execute program first, enter:

 ./hello
 

 Output:

 hello world
 

 WikiPrimaryC ProgrammingC++CCompilergcc
 Prev article

 Graphics (graphics.h) - C Programming

 Next article

 Compile C++ program with g++ compiler on Bash on Ubuntu on Windows 10

 Share Tweet Send

 Discussion

 Community Guidelines

 Latest Articles

 1

 Upgrade Omada Software Controller (Ubuntu Server 22.04)

 2

 Install Omada Software Controller on Raspberry Pi (Ubuntu Server 22.04)

 3

 Auto Mount Drive in Ubuntu Server 22.04 at Startup

 4

 What's new in Xcode 14?

 5

 Prevent External Monitor from Sleep when Macbook AC Adapter Unplugged

 6

 Download Visual Studio 2022 Web Installer / ISO (Community / Professional / Enterprise)

 7

 Download and Install Code Blocks C & C++ IDE on Windows 10 & 11

 8

 Download and Install Borland C++ Compiler on Windows 10 & 11

 9

 Download and Install Code Blocks C and C++ IDE on macOS

 10

 Prevent Invalid Traffic to Websites Ads with Invisible reCAPTCHA

 * iOS 87
 * Primary 74
 * Swift 40
 * C Programming 39
 * Xcode 38

 Newsletter

 Stay up to date! Get all the latest & greatest posts delivered straight to your inbox
 Subscribe
 Great! Check your inbox and click the link to confirm your subscription
 Please enter a valid email address!

 Sign Up To The Newsletter

 Stay up to date! Get all the latest & greatest posts delivered straight to your inbox

 Subscribe
 Great! Check your inbox and click the link to confirm your subscription
 Please enter a valid email address!
 * C Programming
 * C++
 * Data Structure
 * Downloads
 * iOS
 * Microsoft
 * Programming Puzzles
 * Swift Programming
 * Tech
 * Wiki
 * Xcode
 * Interview Question
 * Tips and Tricks
 Copyright 2023, Developer Insider. All Rights Reserved.
 No results found
 ↑ ↓ Navigate up/down
 Enter Go to article
 / Search new term
 Esc Close search
 You've successfully subscribed to Developer Insider
 Great! Next, complete checkout for full access to Developer Insider
 Welcome back! You've successfully signed in
 Success! Your account is fully activated, you now have access to all content.
The GNU Compiler Collection (GCC) is a compiler system produced by the GNU Project supporting various programming languages. You can compile a C program by using the gcc command in Windows 10 Bash on Ubuntu.
If you don't have a enable Ubuntu on Windows check out Stepwise Guide to Enable Windows 10’s Ubuntu Bash Shell (Windows Subsystem for Linux). 
2. Install gcc compiler in Windows 10 Bash
To install gcc compiler in Windows 10 Bash, Open bash and run this command
 apt-get install gcc
 
 
Make sure compiler is installed on your Windows 10 Bash. Type the following command to verify that gcc is installed:
 which gcc
 
 Sample outputs: 
 /usr/bin/gcc
 
Find out version of gcc, run:
 gcc --version
 
 
3. Write your first program on bash
Use a text editor such as nano or vi to create a C program called hello.c:
 nano hello.c
 
 
Type the following lines (program):
 #include &lt;stdio.h&gt;
int main()
{
 printf("hello world\n");
 return 0;
}
 
 
After writing your program, press Ctrl + O and hit Enter key to save your program. To exit nano press Ctrl + X.
4. Compile and Run Program
To compile C program hello.c, and create an executable file called hello, enter:
 gcc hello.c -o hello
 
To execute program first, enter:
 ./hello
 
 Output: 
 hello world
Compile C program with gcc compiler on Bash on Ubuntu on Windows 10
https://developerinsider.co/compile-c-program-with-gcc-compiler-on-bash-on-ubuntu-on-windows-10/