Simple question. I'd like to know how to tell whether the current shell is running as a mc subshell or not. If it is, I'd like to enter a degraded mode without some features mc can't handle.
In particular, I'd like this to
Be as portable as possible
Not rely on anything outside the shell and basic universal external commands.
Though it's not documented in the man page, a quick experiment shows that mc sets two environment variables: $MC_TMPDIR and $MC_SID. (It also sets $HISTCONTROL, but that's not specific to mc; it affects the behavior of bash, and could have been set by something other than mc.)
If you don't want to depend on undocumented features, you can always set an environment variable yourself. For example, in bash:
mc() { MC_IS_RUNNING=1 command mc "$#" ; }
Entering a "degraded mode" is another matter; I'm not sure how you'd do that. I don't know of any way in bash to disable specified features. You could disable selected built-in commands by defining functions that override them. What features do you have in mind?
Related
Uding lldb I defined the following alias : command alias bfn breakpoint set -n %1
Sadly, it does not allow Tab completion as the regular command does. It's a pity because all the time gained in typing the command is lost typing whole identifiers that are sometimes quite complex.
Nevertheless, buit-in aliases allow for completion so I am hoping there's a way to achieve the
same behaviour for user defined aliases.
Are you aware of any solutions to this problem ?
Thansk in advance.
It looks like the problem is with completion in option slots in aliases. The completions work for arguments. I think that’s what you are seeing, not that there’s different behaviors for “internal” and “user” aliases (there isn’t actually such a distinction)…
Every option has its own completer, and lldb isn’t figuring out which slot the positional argument resolves to before handling the completion.
Please file a bug about this with the bugs.llvm.org bug tracker. This should be possible, and would certainly be convenient.
I would like to write shell scripts in a way considered good practice.
An experienced programmer friend advised to use the full pathname for each external command to avoid problems with aliases, functions et al, happening to use the same name as an existing binary, maybe even for malicious reasons. I understand the argument, but short commands (in $PATH) get long very quickly, like:
sudo socketfilterfw --setloggingmode on
becomes
/usr/bin/sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingmode on
This makes quickly grasping what a script does a little harder for me. But maybe I just need to get used to this.
Looking at examples of scripts on github, I do find people doing the same, but most do not.
Is using the full path to a binary considered "good practice"?
No, the generally recommended practice is to rely on the PATH to be correct; or sometimes, if you know the expected location of a program which is not typically already on the PATH, to augment the PATH;
PATH="$PATH:/usr/libexec/ApplicationFirewall"
sudo socketfilterfw --setloggingmode on
Hardcoding the path to a binary means you cannot easily replace it with a customized wrapper for local administrative purposes or debugging; it simply makes everyone's lives harder.
As an aside, a common (but harmless) error is to needlessly export the PATH. Unless you need child processes of the script to inherit the variable, there is no need to export it. (And in practice, you can often be fairly sure the user will already have done that in their login shell; though for system processes which are not always run from an interactive shell, this is not necessarily a given.)
I am writing a shell.
With the execvpe system call, I can run a program and control its environment. What are the minimum values I need to pass through here?
Alternatively, I understand that child processes should have a copy of their parent's environment, possibly with some values added. While testing my shell, I am running it from within bash from within my terminal from within a window manager, etc etc. What are the bare basics that I can assume are in my environment? If I were to run my shell straight from a TTY (the "lowest level", as far as I understand), what can I expect?
That’s a very broad question. To a certain extent,
programs should be able to run with no environment at all.
“X” display (i.e., GUI) programs need to know
where they are supposed to display.
This information is usually provided
through the DISPLAY environment variable,
but can also be passed on the command line.
There are probably other environment variables that are essential
(or nearly so) to “X” programs;
it’s been a while since I’ve looked under that hood.
Any program that needs to use special characteristics of your terminal
needs the TERM environment variable.
“Special characteristics” means being able to set colors
(as ls and grep can do, subject to options),
move around the screen (like vi / vim),
or even know the size of the screen (like less).
Note that size of the screen may also be available
through ROWS and COLUMNS.
Any program that needs to know the date and time
as perceived / understood by the user needs to know the time zone (TZ) —
although, if you’re willing to work with absolute (GMT / UTC),
you don’t need this.
etc.
The minimum that you need is a working PATH variable. Any extras beyond that depend on what programs you want to execute.
POSIX has a list of commonly-used environment variables, very few programs use more than a few of those.
Generally if you're using execvp*, you're not giving full pathnames for the executables. It makes your programs much simpler, you do not have to provide a full pathname for each executable, as is needed by the plain execv. POSIX describes these functions as
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
and (referring to the parameters of the various exec* functions):
The argument path points to a pathname that identifies the new process image file.
The argument file is used to construct a pathname that identifies the new process image file. If the file argument contains a slash character, the file argument shall be used as the pathname for this file. Otherwise, the path prefix for this file is obtained by a search of the directories passed as the environment variable PATH (see XBD Environment Variables). If this environment variable is not present, the results of the search are implementation-defined.
and (remember that "file" is referring to execvp rather than execv, so the environ variable applies to the search using PATH for the "file" parameter):
For those forms not containing an envp pointer (execl(), execv(), execlp(), and execvp()), the environment for the new process image shall be taken from the external variable environ in the calling process.
So... you could technically remove the entire PATH variable, but the result would be implementation-defined.
The minimum neccessary environment is empty. You don't need anything.
e.g.
$ env -i env
$
We can see that env -i has created a blank environment.
We can take this further:
$ env -i /bin/bash
sweh#server:/home/sweh$ env
LS_COLORS=
PWD=/home/sweh
SHLVL=1
_=/usr/bin/env
We can see that bash has set a few variables, but nothing was inherited.
Now such an environment may break some things; e.g. a missing TERM variable means that vi or less may not work properly
$ less foo
WARNING: terminal is not fully functional
foo (press RETURN)
So, really, you need to determine what programs you expect to run inside the environment and what their needs are.
I would like to add documentation for bash functions so that users can lookup the functions with man. There should be no visible difference between my functions and actual commands.
I know I can do this by overriding man with a function that checks for my own functions. Is there another way?
If you have your man pages created (which is a task in itself) then what you can do is put them somewhere on the system like /usr/local/man (or wherever you like, really), then edit the system-wide $MANPATH variable to include that location. Then the man pages will be available.
Real shell functions are not documented by individual man pages but by the help builtin command. You would have to override that. But even I would not look there for information.
Just generate normal man pages and throw them into /usr/local/man/manX or /usr/local/share/man/manX - whatever your distribution already provides. Check /etc/manpath.config that this directory is already mentioned there. That way no one must fiddle in their startup files with the MANPATH environment variable.
Each manpage should also contain a clearly visible section explaining, that this is a function and not a command and what the difference is.
After that the social part kicks in: Tell everyone at every occasion about that documetation. By every I mean every, not only suitable. :-)
I have been spending a lot of time in the shell lately and I'm wondering how the tab autocomplete works. What's the mechanism behind it? How does the bash know the contents of every directory?
There are two parts to the autocompletion:
The readline library, as already mentioned by fixje, manages the command line editing, and calls back to bash when tab is pressed, to enable completion. Bash then gives (see next point) a list of possible completions, and readline inserts as much characters as are identified unambiguously by the characters already typed in. (You can configure the readline library quite much, see the section Command line editing of the Bash manual for details.)
Bash itself has the built-in complete to define a completion mechanism for individual commands. If for the current command nothing is defined, it used completion by file name (using opendir/readdir, as Ignacio said).
The part to define your own completions is described in the section Programmable Completion. In short, with
complete «options» «command» you define the completion for some command. For example complete -u su says
when completing an argument for the su command, search for users of the current system.
If this is more complicated than the
normal options can cover (e.g. different completions depending on argument index, or depending on previous arguments),
you can use -F function, which will then invoke a shell function to generate the list of possible completions.
(This is used for example for the git completion, which is very complicated, depending on subcommand and sometimes
on options given, and using sometimes names of branches (which are nothing bash knows about).
You can list the existing completions defined in your current bash environment using simply complete, to have an impression on what is possible. If you have the bash-completion package installed (or however it is named on your system), completions for a lot of commands are installed, and as Wrikken said, /etc/bash_completion contains a bash script which is then often executed at shell startup to configure this. Additional custom completion scripts may be placed in /etc/bash_completion.d; those are all sourced from /etc/bash_completion.
If you are interested in the basics:
Bash uses readline which features history and basic completion. You could inspect the source if you want to get a detailed understanding.
Furthermore, you can use readline to build your own CLI interfaces with completion