What are those links '"[" & "[[" in /usr/bin - alpine-linux

Busybox creates those links linking to /bin/busybox.
Why are they there and what are they used for?

They're commands used to figure things out in shell scripts. They're usually used to decide between multiple possible actions in shell scripts. For example:
#!/bin/sh
if [ "$1" -eq "5" ]; then
echo You gave me a five.
else
echo You didn't give me a five.
fi
The part that starts with [ checks whether the first argument to the script is 5. To do that, it uses the [ command. [[ is similar but has different capabilities.
The link to /bin/busybox is a trick used by several commands on BusyBox. The /bin/busybox program handles the tasks performed by all of those commands, figuring out which command to perform by looking at which command you originally used to start up /bin/busybox.
This is to save some space on the disk by not having to duplicate things like executable file headers and common functionality and so on for each executable file.
Instead, there's only one executable file for a bunch of commands, so there's only one file header and the common functionality only needs to be included in one file, allowing tricks like static linking without a bunch of duplication, which is nice for embedded systems.

Related

Autoconf : How to get program output in a string and check if another string is present in that

I am developing a Qt application in Python. It uses a resource file, which needs to be compiled. I am using autotools to manage compilation and installation of my projects.
Now, in order for the resource file to be usable by the application, it needs to be compiled with a certain version of the compilation program (pyrcc). I can get the version by putting the output of pyrcc -version in a variable in configure.ac. But then, I don't know how to check whether the string pyrcc5 is present in the output. If it is not present, I want to tell the user that his PyRCC programm has the wrong version, and abort configure.
Additionally, I would like to avoid the need of an extra variable for the program output, but instead do it like this (Pseudo code):
if "pyrcc5" not in output of "pyrcc -version":
say "pyrcc has wrong version"
exit 1
How can I do this ?
When writing a configure.ac for Autoconf, always remember that you are basically writing a shell script. Autoconf provides a host of macros that afford you a lot of leverage, but you can usually at least get an idea about basic "How can I do X in Autoconf?" questions by asking instead "How would I do X in a portable shell script?"
In particular, for ...
I would like to avoid the need of an extra variable for the program
output, but instead do it like this (Pseudo code):
if "pyrcc5" not in output of "pyrcc -version":
say "pyrcc has wrong version"
exit 1
... the usual tool for a portable shell script to use for such a task is grep, and, happily, the easiest way to apply it to the task does not require an intermediate variable. For example, this implements exactly your pseudocode (without emitting any extraneous messaging to the console):
if ! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null; then
echo "pyrcc has wrong version"
exit 1
fi
That pipes the output of pyrcc -version into grep, and relies on the fact that grep exits with a success status if and only if it finds any matches.
You could, in fact, put exactly that in your configure.ac, but it would be more idiomatic to
Use the usual Autoconf mechanisms to locate pyrcc and grep, and to use the versions discovered that way;
Use the Autoconf AS_IF macro to write the if construct, instead of writing it literally;
Use standard Autoconf mechanisms for emitting a "checking..." message and reporting on its result; and
Use the standard Autoconf mechanism for outputting a failure message and terminating.
Of course, all of that makes the above considerably more complex, but also more flexible and portable. It might look like this:
AC_ARG_VAR([PYRCC], [The name or full path of pyrcc. Version 5 is required.])
# ...
AC_PROG_GREP
AC_CHECK_PROGS([PYRCC], [pyrcc5 pyrcc], [])
AS_IF([test "x${PYRCC}" = x],
[AC_MSG_ERROR([Required program pyrcc was not found])])
# ...
AC_MSG_CHECKING([whether ${PYRCC} has an appropriate version])
AS_IF([! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null], [
AC_MSG_RESULT([no])
AC_MSG_ERROR([pyrcc version 5 is required, but ${PYRCC} is a different version])
], [
AC_MSG_RESULT([yes])
])
In addition to portability and conventional Autoconf progress messaging, that also gets the builder a way to specify a particular pyrcc executable to configure (by setting variable PYRCC in its environment), documents that in configure's help text, and exports PYRCC as a make variable.
Oh, and I snuck in a check for pyrcc under the name pyrcc5, too, though I don't know whether that's useful in practice.
The final result no longer looks much like the shell script fragment I offered first, I grant. But again, the pure shell script fragment could be used as is, and also, the fully Autoconfiscated version is derived directly from the pure script.

Files: bash_profile zhrc confusion

I am not sure this is clear to me and if is neat for my system. I'm aware of the ~/.zhrc file where I can store alias and paths, but today after installing node via brew I was asked to put this: export PATH="$HOME/.npm-packages/bin:$PATH" in my ~/.bash_profile file, which it doesn't exist, thus in my effort to keep my system clean I putted it in the former file but emacs complaint. Now, I removed it and putted it, after creating, in the ~/.bash_profile. Is that OK to keep both in the home directory?
You need to provide the exact wording of whatever error or warning message you
get from emacs to ensure accurate or better answers. However, I will make a
guess and assume the warning you are getting is from the exec-path package.
This package has a check, which you can disable, that looks to make sure you
have variables defined in the correct init file.
In general, most shells support two types of configuration files
Startup or Login init files
Interactive shell init files
The difference is how often or when the files are sourced (loaded). To
understand the difference, you really need to understand when a shell is run and
the relationship between each shell. I'll try to give a vary high level
explanation, but you really should read the manual page for the particular shell
you are using.
Think of your environment as a tree of shell processes. When you login to the
system, a login shell is created. This shell will be the parent of all the other
shells you create. Each time you run a command, it is executed in a new shell
(this isn't 100% accurate, but is accurate enough to explain the main
points). So when you open a terminal, it runs another shell which is a child of
your login shell. When you execute various commands, the system creates a new
shell and runs that command inside the shell. These are all children of your
parent login shell. Some shells only exist for a short period of time (as long
as it takes to execute the command), others may last for hours, days or possibly
weeks (such as the shell that emacs is running in).
The important point to keep in mind is that child shells inherit various
settings from the parent shell. The idea of the 'export' command you will see in
front of some variables is actually a command to the shell telling it to export
the variable to child shells. For example, if we have a line like
export PATH=/usr/local/bin:/usr/bin:/bin
what we are really doing is
PATH=/usr/local/bin:/usr/bin:/bin # set the variable
export PATH # make it available in child shells
We don't always want variables to be exported as some variables need to be reset
in the child shell itself. For example, the variable holding the prompt string.
It would not work to have this variable only defined in the login parent shell
if you want the prompt to have dynamic components, such as the current
directory, date or time. We want these types of variables to be defined in each
shell when it is created.
To handle this, shells have the two different init files. The login init files
are only sourced for the parent shell and are particularly useful for setting
variables that will be common to all child shells. the per-shell init files are
sourced for every new shell and are best used for setting things which need to
be updated or changed each time a shell is started. There are also other shell
configuration files which can be used for other special purposes, such as when
you log out or log off a system, or to just put alias definitions in etc.
Once upon a time, it made a big difference where you put your variables as there
was a performance hit when sourcing these init files. If the per-shell init file
was too large and consumed too many resources, the whole performance of your
environment could be affected. This is largely less of an issue these days due
to increased processing speeds. Unfortunately, because many people didn't
understand the role and relationships between the different shell configuration
files, there is lots of incorrect or misleading information out there regarding
where values should be set. People often advise setting variables in (for
example) bashrc when they should be set in the bash__profile=. The confusion is
partly caused by the fact you can add a variable to bashrc and it will work when
you test it (usually because your test involves forking a new child shell) and
putting it in your bash_profile will only work after the next login.
There are also some platform differences which make things a little less
clear. For example, under OSX, there is actually a special file in the /etc
directory where you should add additional path components (I'm not on a mac just
now, but it is something like /etc/paths or a per path component file in
/etc/path.d). This is done so that you have a global place to set paths which
will ensure desktop processes, such as the dock, which do not run as a child
process of your login shell, are able to be set.
As a general rule, most variables can go in the login profile, with the
exception of variables relating to the prompt or other variables which have a
dynamic content i.e. content which changes depending on time, directory
location or other tracking of interactive actions which are specific to a shell
instance.
Setting of the path (noting OS differences as described above) should go into
the profile or login configuration file. Under bash, this is .bash_profile and
under zsh, it is typically .zprofile. As bash has become the most common shell,
documentation etc often advises adding things to .bash_profile. If your running
zsh, then add the same information using .zprofile.
As you have said you don't have a.bash_profile, but you do have a zshrc file, I
am assuming you are running zsh rather than bash as your login shell. This being
the case, you need to add that path setting to .zprofile in your home
directory. The exec-path package is complaining because you added it to
zshrc/bashrc, which are not the correct place to set path variables. If your
running under OSX, you really need to add the path to the correct file in /etc
(you will need to check the OSX documentation as I cannot remember the precise
filename).

Using Perl modules vs. using system() calls

Quite recently, I wrote a few scripts in Perl for a cPanel plugin in which, though most of the code was in Perl, there was quite a lot of system() commands as well which I used to execute shell commands directly.
I am pretty sure that there are Perl modules that I could have used instead. Keeping in mind the time crunch, I thought using the system command was easier (to complete the project in time). In retrospective, I think that was a bad programming practice.
My question is, is there any tradeoff, memory-wise or otherwise when using Perl's modules and using system() commands. For example, what would be the difference in using:
my $directory = "temp";
mkdir $directory;
and
system ("mkdir temp");
Also, if I am to use Perl modules, wouldn't that involve installing a whole lot of modules in the beginning?
The most obvious economy is that, in the first case, your Perl process is creating the directory, while in the second, Perl is starting a new process that runs a command shell which parses the command line and runs the shell mkdir command to create the directory, and then the child process is deleted. You would be creating and deleting a process and running the shell for every call to system: there is no caching of processes or similar economy.
The second thing that comes to mind is that, if your original mkdir fails, it is simple to handle the error in Perl, whereas shelling out to run a mkdir command puts your program at a distance from the error, and it is far more awkward to handle the many different problems that may arise.
There is also the question of maintainability and portability, which will affect you even if you aren't expecting to run your program on more than one machine. Once you abandon control to a system command you have no control over what happens. I could have written a mkdir that will delete your home directory or, less disastrously, your program may find itself on a system where mkdir doesn't exist, or does something slightly different.
In the particular case of mkdir, this is a built-in Perl operator and is part of every Perl installation. There are also many core libraries that require you to put use Module in your program, but are already installed and need no further action.
I am sure others will come up with more reasons to prefer a Perl operator or module over a shell command. In general you should prefer to keep everything you can within the language. There are only a few cases where you have to run a third-party program, and they usually involve custom software that allows you act on proprietary data formats.

How can I find out what script, program, or shell executed my Perl script?

How would I determine what script, program, or shell executed my Perl script?
Example: I might want to have human readable output if executed from shell (customized for each type of shell), a different type of output if called as a script from another perl script, and a machine readable format if executed from a program such as a continuous integration server.
Motivation: I have a tool that changes its output based on which shell executes it. I'd normally implement this behavior as an option to the script, but this tool's design doesn't allow for options. Other shells have environment variables that indicate what shell is running. I'm working on a patch to support Powershell, which has no such special variable.
Edit: Many of these answers happen to be linux specific. Unfortuantely, Powershell is for Windows. getppid, the $ENV{SHELL} variable, and shelling out to ps won't help in this case. This script needs to run cross-platform.
You use getppid(). Take this snippet in child.pl:
my $ppid = getppid();
system("ps --no-headers $ppid");
If you run it from the command line, system will show bash or similar (among other things). Execute it with system("perl child.pl"); in another script, e.g. parent.pl, and you will see that perl parent.pl executed it.
To capture just the name of the process with arguments (thanks to ikegami for the correct ps syntax):
my $ppid = getppid();
my $ps = `ps --no-headers -o cmd $ppid`;
chomp $ps;
EDIT: An alternative to this approach, might be to create soft links to your script, make the different contexts use different links to access your script and inspect $0 to build logic around that.
I would suggest a different approach to accomplish your goal. Instead of guessing at the context, make it more explicit. Each use case is wholly separate, so have three different interfaces.
A function which can be called inside a Perl program. This would likely return a Perl data structure. This is far easier, faster and more reliable than parsing script output. It would also serve as the basis for the scripts.
A script which outputs for the current shell. It can look at $ENV{SHELL} to discover what shell is running. For bonus points, provide a switch to explicitly override.
A script which can be called inside a non-Perl program, such as your continuous integration server, and issue machine readable output. XML and/or JSON or whatever.
2 and 3 would be just thin wrappers to format the data coming out of 1.
Each is tailored to fit its specific need. Each will work without heuristics. Each will be far simpler than trying to guess the context and what the user wants.
If you can't separate 2 and 3, have the continuous integration server set an environment variable and look for it.
Depending on your environment, you may be able to pick it up from the environment variables. Consider the following code:
/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh
On my Ubuntu system, it gets me:
'SHELL' => '/bin/bash',
So I guess that says I'm running perl from a bash shell. If you use something else, the SHELL variable may give you a hint.
But let's say you know you're in bash, but perl is run from a subshell. Then try:
/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh
You will find:
'_' => '/bin/sh',
'SHELL' => '/bin/bash',
So the shell is still bash, but bash has a variable $_ which also show the absolute filename of the shell or script being executed, which may also give a valuable hint. Similarily, for other environments there will most probably be clues left in the perl %ENV hash that should give you valuable hints.
If you're running PowerShell 2.0 or above (most likely), you can infer the shell as a parent process by examining the environment variable %psmodulepath%. By default, it points to the system modules under %windir%\system32\windowspowershell\v1.0\modules; this is what you would see if you examine the variable from cmd.exe.
However, when PowerShell starts up, it prepends the user's default module search path to this environment variable which looks like: %userprofile%\documents\windowspowershell\modules. This is inherited by child processes. So, your logic would be to test if %psmodulepath% starts with %userprofile% to detect powershell 2.0 or higher. This won't work in PowerShell 1.0 because it does not support modules.
This is on Windows XP with PowerShell v2.0, so take it with a grain of salt.
In a cmd.exe shell, I get:
PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\
whereas in the PowerShell console window, I get:
PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP
owerShell\v1.0\Modules\
where E:\Home\user is where my "My Documents" folder is. So, one heuristic may be to check if PSModulePath contains a user dependent path.
In addition, in a console window, I get:
!::=::\
in the environment. From the PowerShell ISE, I get:
!::=::\
!C:=C:\Documents and Settings\user

Auto-complete command line arguments

In bash, executables such as mplayer and imagemagick's "convert" have a cool auto-complete functionality on their command line arguments. For instance, if I type
mplayer <tab><tab>
in one of my video folders, then mplayer will list all media files located in that folder, and only the media files.
Similarly, if I type
convert -<tab><tab>
then I will see all the possible options of the convert script, which is great.
My question is how to achieve a similar functionality, using bash, ruby or python scripts?
This is an example of BASH's smart completion. A basic description is here, a guide to writing your own extensions is here and another (Debian-based) guide is here. And here's a fuller featured introduction to the complete command (the command that facilitates this behaviour).
The link to writing your own extension in the accepted answer has gone dead. Quoting here from http://web.archive.org/web/20090409201619/http://ifacethoughts.net/2009/04/06/extending-bash-auto-completion/
Bash provides you a way of specifying your keywords, and using them to
auto complete command line arguments for your application. I use vim
as a wiki, task managemer and contacts. The vim helptags system lets
me index the content instead of searching through it, and the speed
shows it. One feature I wanted to add to this was to access these tags
from outside vim.
This can be done in a straight forward way:
$ vim -t tagname
This takes me directly to specific content marked using this tag. However, this will be more productive if I can provide
auto-completion for the tags.
I first defined a Bash function for the vim commandline. I added the
following code to my .bashrc file:
function get {
vim -t $1
} Now I can use get tagname command to get to the content.
Bash programmable completion is done by sourcing the
/etc/bash-completion script. The script lets us add our
auto-completion script /etc/bash-completion.d/ directory and executes
it whenever it is called. So I added a script file called get with the
following code in that directory.
_get()
{
local cur
COMPREPLY=()
#Variable to hold the current word
cur="${COMP_WORDS[COMP_CWORD]}"
#Build a list of our keywords for auto-completion using
#the tags file
local tags=$(for t in `cat /home/anadgouda/wiki/tags | \
awk '{print $1}'`; do echo ${t}; done)
#Generate possible matches and store them in the
#array variable COMPREPLY
COMPREPLY=($(compgen -W "${tags}" $cur))
}
#Assign the auto-completion function _get for our command get.
complete -F _get get Once the /etc/bash-completion is sourced, you will get auto-completion for the tags when you use the get command.
Along with my wiki I use it for all the documentation work and at
times the code too. I also use the tags file created from my code. The
indexing system lets me remember the context instead of the filenames
and directories.
You can tweak this system for any of the tools you use. All you need
to do is get a list of the keywords for your command and give it to
the Bash programmable completion system.
This functionality in bash is provided by bash-completion and similar functionality is included in zsh. If you want to add support for some program not currently supported by one of these tools, you need to write your own extensions for them.
How do I enable bash completion on Ubuntu?
sudo apt-get install bash-completion
source /etc/profile.d/bash_completion.sh
sudo apt i[TAB]