How to implement a new shell command? - linux

I want to implement my own version of ps command & I am trying to understand how shell commands are implemented in Linux. Is it part of the Shell application or part of the module?
In my understanding, when I type ps in shell prompt: the actual implementation for ps can only reside in kernel & shell just invokes a kernel api/binary.
Now, if I want to add a new command (say myps): what should I modify in shell application? & What should I modify in kernel module?
How shell application knows the list of commands supported in individual modules (kernel, network, fs, etc) ?
Lastly, if (just for example) network module is configured & built only for ipv4 and then there is no point in supporting ipv6 commands in shell? How is this taken care?

ps is just a regular program (typically located at /bin/ps). You can find its location on your system by running which ps.
When you run a command (assuming it's not a builtin function, alias, etc. implemented by the shell itself), the shell searches the directories listed in your PATH environment variable. If you're using sh or bash as your shell, you can see it by running echo $PATH. The shell searches the directories in the order they're listed in PATH, and runs the first matching program it finds.
If you want to create a new version of ps, just write a program and put it in one of the directories on your PATH. Typically somewhere like /usr/local/bin/ (accessible by all users) or ~/bin (in your home directory). Or you could add a new directory to your PATH. No need to mess with the kernel or the shell itself, thankfully.

Related

When can I run a shell script with command ". shellscript" in bash,ubuntu?

If I have a script "shellscript" in /usr/bin directory(It can also be a script of an installed program). When I run command "shellscript" (from anywhere , home or other directory) in terminal, it runs perfectly but when I use ". shellscript" , then also this file executes.
I know we can use ". /path/to/script/shellscript" to run it but if its in /usr/bin , can we use direct command without path?
Is it safe to run?
Can we run programs in such a way?
I need explanation. If yes then why? If Not then why? Should not then why?
The Bash shell searches the directories listed in the PATH variable in both shellscript and . shellscript cases. The main difference is that when using . (or equivalently source) to start a script, a new shell process is not created for interpreting the script. This is sometimes useful because it allows the script to define environment variables and functions that will then be available in the caller. For more details, see the Bash manual page (info bash).

Linux basics - automating a script execution

When beginning to work, I have to run several commands:
source work/tools
cd work/tool
source tool
setup_tool
Off course, doing this a few times a day is really annonying, so I tried to make a bash script tool where I put these commands and put it in /user/bin to run it with command
tool
However, there is a problem. When i run the script and then try to work by typing some of the tool-based commands, it does not work.
I figured out, that it is fine, since if I make a script and then run it, the script seems to run in the same terminal window, but what it really does is, that it behaves as if it created a "hidden window" for its execution and after termination of the script, the "hidden window" terminates too. So I am asking - is there a way to automatize the source command?
I have tried using xterm -hold -e command, but it runs the programmed script in the new window. Obviously, I don't want that. How can I achieve running it in the current window?
Don't put files like that in /usr/bin. As a general rule you don't want to mess with the distribution owned locations like that. You can use /usr/local/bin if you need a system-wide location or you can create a directory in your home directory to hold things like this that are for your own usage (and add that to the $PATH).
What you've noticed is that when run as a script on its own (tool, /path/to/tool, etc.) that the script runs in its own shell session (nothing to do with terminal windows as-such) and you don't want that (as the changes the script makes don't persist to your current shell session).
What you want to do instead is "source"/run the script in your current session. Which you are already doing with that set of commands you listed (source work/tools is doing exactly that).
So instead of running tool or /path/to/tool instead use source /path/to/tool or . /path/to/tool.
As fedorqui correctly points out you don't even need a script for this anywhere as you can just make a shell function for this instead (in your normal shell startup files .bashrc, etc.) and then just run that function when you need to so that setup.
Be careful to use full paths for things when you do this though since you, presumably, want this to work no matter what directory you happen to be in when you run it.
It doesn't create a new hidden window, nor does it create a terminal. What happens is that if you're running a script, normally it runs on a new shell process. The script you're running is supposed to modify the shell environment, but if you're running the script in a new shell process, that shell process's environment is the one that gets modified, instead of your shell environment.
Scripts that needs to modify the current shell environments usually must be run with the source command. What you need to do is to run the script in the current shell. So you should do source /path/to/tool.
If you want to be able to source the script with just tool, put this in your alias file/shell startup (check your distro doc where the file is, but it's usually either .bash_aliases or .bashrc):
alias tool="source /path/to/tool"

Shell commands are written in what language?

There are many shell commands, like
ls, cd, cat etc.
what programming language is used in writing these commands? How are they compiled?
My understanding:
Shell is a program which takes command; ** does this mean that it interprets those commands(like ls is interpreted by shell program)?**
One more question, what language is Shell program written in?
Most of the basic utilities in linux are written in C .This u can verify in busybox source code which supports most of basic linux command utility which are written in C.
So command like ls,cd ...etc are in c
How shell will interpret check in below link
in an operating system there is a special program called the shell. The shell accepts human readable commands and translates them into something the kernel can read and process.
http://www.math.iitb.ac.in/resources/manuals/Unix_Unleashed/Vol_1/ch08.htm
These programs are mainly written in the C programming language as is the linux kernel.
The programs are ordinary executable written in any language (mostly C).
The shell takes a command entered which is just a string. It then looks for certain sequences of characters which have special meaning to the shell such as environmental variables which are $ followed by a word or redirects which are > followed by a path. After this substitution has been preformed it has a string which is split on spaces to generate a name of an executable and parameters. The shell will then search for the executable in the list of directory's in the environmental variable PATH. The shell then uses system calls to create a process from the executable with the parameters.
For example to execute the command ls $HOME the shell would first recognize that $HOME is an environmental variable and substitute it for its value in this case /home/user leaving the command ls /home/user. It then splits the command to on the space to get the executable name ls and parameter /home/user. The shell finds the first executable that matches ls usually /bin/ls. It then uses ether the spawn()/ posix_spawn() or fork() and exec() system calls to create the new process.

How does the shell know which directory it's in?

I have been trying to figure out how a shell knows which directory you're currently in. I know there is an environment variable $PWD but when I try changing it manually, it changes what my shell shows at the prompt but commands like ls and cd are unaffected.
cd is an internal shell command so I can understand it might use info stored within the shell memory, but ls is external and yet running ls without anything will give me whatever directory I was originally in regardless what I do to $PWD.
Each process has its own individual current working directory which the Linux system tracks. This is one of the pieces of information the OS manages for each process. There is a system call getcwd() which retrieves this directory.
The $PWD environment variable reflects what getcwd() was the last time the shell checked, but changing it does not actually change the current directory. To do that the shell would have to call chdir() when $PWD changes, which it does not do.
This also is the reason cd has to be a shell built-in. When you run a sub-process that child process gets its own working directory, so if cd were an executable then its calls to chdir() would be useless as that would not change its parent's working directory. It would only be changing its own (short-lived) working directory. Hence, cd is a shell built-in to avoid a sub-process being launched.
The shell sets that variable, but stores the knowledge internally (which is why you can't make cd an external program, it must be a built-in). The shell prompt is composed just before it is displayed each time, and you have specified using $PWD in yours, so the shell reads that in.
Remember: the shell is just a program, like any other program. It can---and does---store things in variables.
As AndiDog and John point out unix-like systems (i.e. including linux) actually maintains the working directory for each process through a set of system calls. The storage is still process local, however.
The Linux kernel stores the current directory of each process. You can look it up in the /proc filesystem (for example, "/proc/1/cwd" for the init process).
The current directory can be changed with the chdir syscall and retrieved with getcwd.
The current directory is a property of a running program (process) that gets inherited by processes created by that process. Changing the current directory is made via an operating system call. The shell maps the cd operation to that system call. When you write an external program like ls, that program inherits the current directory.
The $PWD variable is how the shell shows you the current directory for you to use it as a variable if you need it. Changing it does not have effect in the real current directory of the shell itself.
You (OP) launch ls via your command shell, and any process you launch, the shell launches in the context of its current working directory. So, each process you launch has its own $PWD variable (in a way).

Location of cd executable

I read that the executables for the commands issued using exec() calls are supposed to be stored in directories that are part of the PATH variable.
Accordingly, I found the executables for ls, chmod, grep, cat in /bin.
However, I could not find the executable for cd.
Where is it located?
A process can only affect its own working directory. When an executable is executed by the shell it executes as a child process, so a cd executable (if one existed) would change that child process's working directory without affecting the parent process (the shell), hence the cd command must be implemented as a shell built-in that actually executes in the shell's own process.
cd is a shell built-in, unfortunately.
$ type cd
cd is a shell builtin
...from http://www.linuxquestions.org/questions/linux-newbie-8/whereis-cd-sudo-doesnt-find-cd-464767/
But you should be able to get it working with:
sh -c "cd /somedir; do something"
Not all utilities that you can execute at a shell prompt need actually exist as actual executables in the filesystem. They can also be so-called shell built-ins, which means – you guessed it – that they are built into the shell.
The Single Unix Specification does, in general, not specify whether a utility has to be provided as an executable or as a built-in, that is left as a private internal implementation detail to the OS vendor.
The only exceptions are the so-called special built-ins, which must be provided as built-ins, because they affect the behavior of the shell itself in a manner that regular executables (or even regular built-ins) can't (for example set, which sets variables that persist even after set exits). Those special built-ins are:
break
:
continue
.
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset
Note that cd is not on that list, which means that cd is not a special built-in. In fact, according to the specification, it would be perfectly legal to implement cd as a regular executable. It's just not possible, for the reasons given by the other answers.
And if you scroll down to the non-normative section of the specification, i.e. to the part that is not officially part of the specification but only purely informational, you will find that fact explicitly mentioned:
Since cd affects the current shell execution environment, it is always provided as a shell regular built-in.
So, the specification doesn't require cd to be a built-in, but it's simply impossible to do otherwise.
Note that sometimes utilities are provided both as a built-in and as an executable. A good example is the time utility, which on a typical GNU system is provided both as an executable by the Coreutils package and as a shell regular built-in by Bash. This can lead to confusion, because when you do man time, you get the manpage of the time executable (the time builtin is documented in man builtins), but when you execute time you get the time built-in, which does not support the same features as the time executable whose manpage you just read. You have to explicitly run /usr/bin/time (or whatever path you installed Coreutils into) to get the executable.
According to this, cd is always a built-in command and never an executable:
Since cd affects the current shell execution environment, it is always provided as a shell regular built-in.
cd is part of the shell; an internal command. There is no binary for it.
The command cd is built-in in your command line shell. It could not affect the working directory of your shell otherwise.
I also searched the executable of "cd" and there is no such.
You can work with chdir (pathname) in C, it has the same effect.

Resources