Depends upon the system. In my system, it does write to stderr:
$ which abcdasdf 1>/dev/null
which: no abcdasdf in (/usr/lib/mpi/gcc/openmpi/bin:/usr/local/bin:/usr/bin:/bin:.....snip)
$ uname -srv
Linux 3.4.47-2.38-desktop #1 SMP PREEMPT Fri May 31 20:17:40 UTC 2013 (3961086)
I'm intrigued by your uname command. What kind of information adds to this case? Honest question, I would have expected the following command to provide context:
$ which --version | head -1
GNU which v2.20, Copyright (C) 1999 - 2008 Carlo Wood.
Or may be the output of lsb_release, although it may not be installed in your system.
Is "which" behaviour dependant on the kernel version?
EDIT: formatting; also to add that which writes to stderr if the command you're asking for can't be found in the path.
function debug()
{
if [ -v VERBOSE ]
then
echo "${1}" # might want to add: >2
fi
}
function has_dep()
{
unset dependency
dependency=$(command -v "${1}")
if [ -v dependency ]
then
debug "found \"${1}\": ${dependency}"
return 0
else
debug "\"${1}\": not found"
return 1
fi
}
# example:
VERBOSE=1
if has_dep curl
then
echo "we're good"
fi
if has_dep notfoundthing
then
echo "not good."
fi
Betty:srcs lelf$ perl -E 'say "out"; say STDERR "err";' &> out && cat out
err
out
Betty:srcs lelf$
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
Plus if your script supports both `--version` and `--help` with proper formats, you can easily generate a manual page with `help2man`. The help output example is far from that. Also, he does not mention getopt at all.
$ ./test foo bar --help --version
--help --version -- foo bar
Which can be parsed using a `while` loop with `shift`.
For other tips on shell scripting best practices I recommend Gentoo ebuilds. They tend to be quite well written. And always read scripts from other people before running them yourself.
Thank you for correcting this post for all us Bash gurus out here.
Also I would like to point out that you shouldn't keep using capital letters in your scripts because it might clash with environment variables. Treat them just like any other programming language, underscores or camel case for example.
I'd like to say "What I learned from idling in #bash on freenode" instead. That's a much better lesson.
I always wanted a shell best practices book (for formatting, beyond the TLDP Advanced Bash Guide, or dare I even say the POSIX spec). I will definitely checkout the Gentoo ebuild scripts. I used to look at Debian in my youth to try and find someone to imitate.
However, are there are any people writing lint or prettify or Perl Critic like progs or web services that will properly wrap and do things you mention?
Would there be interest in such a thing?
UPDATE: I found this stuff. Does anyone use these things?
A (cheap) trick for formatting shell scripts is approximately:
wrap script into a shell function
source function definition
diff defined function against script
with something like:
{ printf 'dummy (){ '
cat script
printf "; };\ntype -a dummy\n"
} > dummy
source dummy > defined
rm dummy; unset -f dummy
diff script defined
Issues include:
comments are absent from defined function listing
trailing semicolons appear after each shell command / line
the first semi in the trailing "; };" may be a syntax error
The default function listing format is fairly generic, so personal
formatting preferences must be left as an exercise for the reader.
MHO: people who insist on specific code formats should provide tools
that can convert arbitrary code into their preferred format.
Also found very cool meet me in the middle type projects, where you can interact with Shell in different programming languages, or "transpile" to it like CoffeeScript -> Javascript.
The most interesting so far: Sh.py [0] (mentioned here before [1]) and plumbum [2], which is surprisingly extensive.
Shell scripts have their use but at the point when your script needs output coloring or printing debug information, it is time to switch to Python.
Edit: Place a general disclaimer to weaken the absolute tone of the above statement. Rule of thumb, exceptions apply, yadda, yadda. In other words, I somewhat agree with most responses that disagreed with the statement above :-)
I get what you mean, but there are reasons for shell scripts to stay shell scripts, and not move to Python. One such project [0] is patching Android to allow for a privacy framework. What would Python offer me for diffing and patching that cleanly written shell scripts would not?
Shell is still good for one thing: piping commands together. You can do that in Python, but I think even complicated output coloring and debugging scripts should stick to shell when the focus is piping utilities in and out of each other. Python can do that, but it is not its sweet spot, in my opinion. I am sure others disagree.
Agreed. Piping and a few of the other syntax niceties ('&&' for conditionally chaining processes is my favorite) are a hard match for even the best process-management library you might have in a general purpose language. Maybe a Lisp DSL could match that, I don't know.
Does it still work well? I am very interested in this. I really like Chicken Scheme because it compiles to portable C, and I was wondering why there has not yet been a Scheme shell this morning.
Guess I was naive to think there was not without a proper Google-fu session.
UPDATE: I take that back, it appears some still works on it. That page just seems outdated, by a while now.
Disclaimer: I haven't used it and the author says it is "still pretty new." However, it seems to be under active development still. At least there was a commit to the repository within the last year.
I use these languages in ascending order for sys-admin/config:
shell -> perl -> python.
On OpenWRT systems, sometimes even microperl won't fit. All you've got is shell. (and sh only, none of this fancy bash stuff(1)) Its good to be able to do things at many levels.
At my first "real" job I used to work on a RS-6000, a couple hundred-grand machine. The admin wouldn't install _anything_ non-stock other than a JVM on it. It taught me how to get around using only BSD Unix tools and Bourne Shell. It was an enormous pain in the butt, but what I learned has been utterly invaluable over the course of my career.
I use awk from time to time, specially when I need to process a file line by line and the task is too simple to use python (ie. an awk one-liner will do!).
Or Perl, of course. Although I've seen some pretty big collections of shell scripts used for deployment, configuration etc, and all that in a rather heterogeneous Unix environment. Then again, that was Korn Shell, which supports larger programs a bit better than plain bash.
I tend to think of colouring and debug output as standard shell script boilerplate.
I typically switch to Python (or similar) when I need something like multidimensional arrays / dicts (not portable in awk), or in general want to run more complex parsing or transformations on input. The more advanced string functions of bash I always have to look up (is it ## or %% that removes from the start of the string?), and for/while loops are in general a lot slower.
But for file system operations, stringing together commands, keeping track of backgrounded commands (using multiple threads without even thinking about it), and even turning arbitrary programs into "daemons" (using fifo's), nothing beats shell scripting.
- Filesystem operations. How many times have we seen programs using "ls * .foo" when they needed to use "find -name '*.foo'" to avoid command-line length limits? I answered this very question on StackOverflow this week. How many seemingly-capable software shops will churn out shell scripts which misbehave when a path has a space or other "weird" character in it? Even Apple fell prey to that one, about ten years ago, and destroyed some users' data.
- Stringing together commands. This encourages abominations like "cat myfile | grep foo | awk '...'". Just use awk if you're into that, but the shell has a knack for "tricking" people into spawning extra processes that are not really needed (indeed this is one of the most frequent performance sinks in shell scripts). And what about error handling for the several subprocesses? It's usually ignored for N-1 of them.
- Keeping track of backgrounded commands (using multiple threads without even thinking about it). Yes, you can use multiple cores without thinking--that can be cool. But what if you want to do N units of work on many fewer than N cores? You ought to use a pool, but there's no such thing in Bash. Maybe you're clever and use "xargs -P" for this, but most people don't.
- Turning arbitrary programs into "daemons". I use start-stop-daemon for that (it's included in Debian, and I easily wrote a workalike in Python when I had to use a system that didn't support it natively).
Just about the only thing here that shell scripts are really good for is doing things "without even thinking about it." Once when I was asked why shell scripting was not a good idea for production programs, I reviewed a smallish sample Bash script that had been deployed. I found a dozen latent bugs, 50% of which would have never have happened with Python (or Go, or...).
Stringing together commands is the primary reason I write most of my scripts in bash; because my commands are generally written in multiple different languages. Also, the fact that the shell is a REPL, means scripts can be prototyped or even assembled from shell history fairly easily, then refactored into something better resembling usability.
Re performance, I usually run Cygwin on Windows. Starting up too many processes is not a mistake I tend to make, because forking in Cygwin is hopelessly slow. Similarly, spaces in paths are common, and I've learned to be fairly religious about quoting, to the point of using print0, xargs -0 etc.
My scripts regularly deal with millions of files, and pipes that transfer tens of gigabytes. I rely on being able to string together sort and uniq to do set operations over multi-gigabyte files with constant memory usage; such scripts are not trivially rewritten in languages like Python without using non-standard libraries. When performance becomes an issue, the solution is a lot more heavyweight in terms of development time.
Fair enough; Unix certainly gives you enough ways to shoot yourself and your customers in the foot. I probably should've added the qualifier "wrt. succinctness" (that's e.g. the reason I move from awk to Python when I need more complex data structures than awk's arrays, which can often do the job, but not without looking ugly).
By the way, your "ls * .foo" does not even do the same as "find -name '*.foo'" due to a superfluous space ;-)
But the fact that most people don't know about xargs -P (or gnu parallel), or spawn too many processes, or use ugly hacks like pidfiles/start-stop-daemon, is not a reason to throw out all the good stuff shell scripting has to offer.
> "cat myfile | grep foo | awk '...'" […] indeed this is one of the most frequent performance sinks in shell scripts
Is it really? I would've thought loops were a more common performance sink. I can't imagine how that useless use of cat has _that_ much of an effect, unless you're running a whole bunch of copies of this script. It looks ugly in the process table and it does not let the real command (here: grep) move back and forth in the file, but I've never noticed performance improvements from removing uuoc's.
My original phrasing may have been unclear; with the elision you made the thrust becomes quite different. I intended to convey two thoughts: that Useless Use of Cat and other filters is pervasive because it is so easy, and secondly, that spawning tons of unnecessary processes is a common performance waste. The specific example with just three processes (cat, grep, awk) is not such a big deal--the bad cases are when stuff like that happens within loops (but the performance loss is not due to the loops, but rather the spawning).
I find shell scripts confuses the heck out of me whenever they try to do something a little more complicated the piping.
Even this left me a but confused like how do the functions get the input parameters does the * in echo -e "$RED$*$NORMAL" have something to do with it?
There's just so many obscure ways of doing the same thing not to mention there's very few good places to teach you shell scripting and shell scripting best practices.
I'd rather just go with python. It's easier to read.
Free advice: you almost never want $. Almost always what you want is $@, usually in the form "$@". It doesn't matter for this example, but $ is usually a code smell.
For learning the differences between POSIX sh and bash (which can trip you up if you want to run on systems without bash, or if you simply don't know that #!/bin/sh is different from #!/bin/bash), see http://mywiki.wooledge.org/Bashism
And regarding how to parse your example, the $* in a string expands to all input parameters to the function, separated by the first character of the IFS variable (e.g. space).
Also, there's no reason to use uppercase for all variables, it's just that environment variables are by convention uppercase so people seem to think their local vars need to be uppercase too.
Of course, there are also some people crazy enough to write web apps in C, C++, or dare I say Haskell! The latter has become popular, but every tool has a purpose, and every tool can be re-invented, like if you are a garbage social app so popularly social you compile your PHP into C++ and give it a music genre name.
Python is an ideal replacement for small Java programs, not Shell.
The moment your script needs any more than 10 regular expressions, or dealing with >3 files all in a complex interplay- use of Perl becomes inevitable. And that is something like the very utmost basic thing you can do with Perl.
Python is more like tried-to-be-scripting-but-is-a-web-framework language.
I agree that Python is a general-purpose language that could replace much of the Java code you see around, but I never got the feeling that it is particularly well-suited for the web. For one thing, with significant whitespace, it's harder to embed snippets of code in HTML or vice versa, so you have to work with a templating library right from the beginning. Some will see this as a blessing in disguise, but for very small projects or mostly self-contained components, having logic and presentation in one file is much more productive.
Ironically bulk of all the Python out there is web code.
In fact Django, Twisted and Zope is all the Python code there is.
Scripting was never Python's forte. Scripting is all about succinctness, power and providing as much power with fewer constructs and restrictions. Which happens to be exactly the very opposite of Python goals, and some thing which more or less as a mission statement Python tries to achieve. This is why Python will likely never be a very successful scripting language.
Python was always a web language for frustrated java programmers who couldn't put with java's problems anymore. Much of Python's success is in web frame work area. Which was previously Java's territory.
Yes, Python is obviously used for web development. But it's very short-sighted, and even absurd, to claim that the "bulk of all the Python out there is web code".
It's even more absurd to claim that "Django, Twisted and Zope is all the Python code there is." That's utter nonsense, in fact.
There are numerous non-web applications that use Python extensively, whether they're partially or fully implemented in Python, or whether they can be scripted using Python.
Then there are the numerous libraries and frameworks for Python, from GUI toolkits through to scientific computation packages.
Many, many organizations use Python internally for a very wide variety of tasks and systems, without broadcasting such use loudly, if at all. This ranges from one-off scripts up to entire multi-million-line software systems.
I sure hope that you're joking, but it just isn't coming across as a joke. Nobody can seriously claim that "Python will likely never be a very successful scripting language" when it has undoubtedly been one of the most successful, and versatile, programming and scripting languages around for many years now.
The biggest reason why Python 3 is/was seeing such late adoption is purely because web frameworks/libraries were not migrated to Python 3. Goes on to tell how many people use Python for what purposes, that absence of a domain of frameworks/libraries slows down the adoption of the language itself for years.
Of course Python is used for scripting purposes. But that amount of code is no where close the web code that is written in Python. It all depends how much code in ratio is written for what purposes and not the total amount of code written for that purposes.
Python's glory days came with web frameworks and continue to be the reason for its fame and wide spread adoption.
I will take Python seriously if it offers the same capabilities as Perl at least on the command line.
Python is a awesome general purpose language. But so far as scripting is concerned it is still no match to Perl
Like I tried to explain to you earlier, those who use Django and the other Python web frameworks that may not really support Python 3 yet are a very small portion of the entire Python user community.
Many of the rest of us have been happily and very successfully using Python 3 for years now, including for the scripting tasks that you incorrectly claim we don't use Python for.
Your other claims like "Python's glory days came with web frameworks and continue to be the reason for its fame and wide spread adoption." are truly absurd and outright wrong. Python was very popular and widely used well before the mid-2000s, when many of the web frameworks you're referring to were first released.
I think you vastly overestimate the amount of Python used for web applications, as well. This is understandable, as such uses are often more visible than the other behind-the-scenes uses. But there's a staggering amount of Python code that you don't see, and that isn't used for web applications.
> The biggest reason why Python 3 is/was seeing such late adoption is purely because web frameworks/libraries were not migrated to Python 3.
That is a pretty big assumption to make, in my opinion.
When we're talking in the context of scripting then we should be talking about what distros have easily accessible python3 packages/libraries, good python3 community support, and whether libraries relevant to sysadmin scripting tasks have been ported to python3 or not.
Python is great for many things, but sometimes you need something lighter. That's not to say that Python is heavy -Java is heavy- but there are environments so constrained that even Python is not light enough. This is where shell scripts can come in handy.
Regarding traps, I struggled for a while with getting a robust and simple way to kill backgrounded scripts on exit. I would have a script do stuff like "sort bigfile & pid=$!; runlongtask; wait $pid", and on Ctrl-C I wanted the sort command to stop too. The trick is to use "kill 0", which kills the non-interactive script and its subprocesses (see "man 2 kill"). So say you want to both remove some temp directory and kill all subprocesses on Ctrl-C, put this at the top of your script:
I second that! Every shell script should start with "set -e -u": exit if any command fails (except if called as a condition) or if an unset variable is used.
Usually, you never want your script to continue running after a command unexpectedly fails or you use an unset variable. Saves so much time debugging!
A good gem I found recently was to use the big version of the command line flags. So instead of seeing -s -q 1, you should use arguments like --max-depth. Increases the readability of scripts by a huge margin.
To be fair, with some commands there are flags which do different things in OSX/BSD and in GNU. So you should verify that all arguments, both short and long, do the same thing
As an example, `sed -i` is used for in-place editing. BSD/OSX variants expect an extension argument to be provided after the flag, with an empty string for no backup (sed -i '' 's/foo/bar/' foo.bar)
On the other hand, gnu expects the backup extension in the flag (like -W in C compilers), so the command is parsed as if 's/foo/bar/' was the file to open
My favorite discovery is how to efficiently do RPC style calls in BASH. Let's say you have some functions and variables you want to execute on a remote server. Just do the following:
In this example, var1, var2, var3 and func1, func2 are support variables/functions for the function "remotemain". This pushes all those to the remote side, then calls remotemain.
A while ago I was working on a bash function library. The library itself may not be that usefull but it also contains some examples on how to color output and move the cursor around. http://code.google.com/p/bsfl/
As someone who is learning PHP as his first programming language, I am surprised to see similarity in terms to syntax with shell scripts. Are there other popular language with php-like sytax?
Also, even if ^J or ^M were present in a parent directory's name, the command above would still work. Whitespace-like characters take some getting used to with Bash.
Browse this website and you will learn a lot about bash. Opinionated at times, but that's what I like. If you use Bash scripting you've might encountered this site already, but for what it's worth:
http://mywiki.wooledge.org/BashFAQ
I wrote a silly script for noob openbsders like yours' truly: it builds the usage from functions' comments in the script on-the-fly. https://gist.github.com/6120072
All this article does is make me wish there were an alternative to typical Borne shell garbage. No sane person would ask for a wretched pile of hacks like this.
Sadly, much of this article is an example of why you shouldn't learn from other people's shell scripts. Too often shell scripts are quickly written without much attention to best practices, so they have a lot of bad habits in them. For much the same reason bad code tends to get copy and pasted about until it becomes common such common practice no one questions it.
One shouldn't use which at all. It forks an external process, it is vulnerable to PATH issues unless you specify what will surely be a non-portable path to the executable, often isn't included in chroot'd environments, and doesn't actually return an exit status on many platforms. In short: it sucks in almost all possible ways you could hope to suck.
The proper expression to use is:
command -v curl >/dev/null 2>&1
If you know you are in bash, type -P and possibly hash become acceptable alternatives, but then... why not just use command -v right?
`2>&1 > /dev/null` will drop stdout and write stderr to stdout.
`> /dev/null 2>&1` will drop both stdout and stderr.
For myself, with `which` I would just use `> /dev/null`, as `which` writes to stdout and not stderr: if anything comes through stderr, you probably want to know about it.
All right, but he wrote: "The 2>&1 > /dev/null puts both output stream and error stream to /dev/null (which means nothing printed on console).". So the intention was different.
PS. I think "which" will never produce anything on stderr
As Chris said, `2>&1 > /dev/null` will drop stdout and write stderr to stdout. If you do not want anything to printed on console, you can use it. Now only i came to know that `which` never produce the stderr. So it is enough to use `>/dev/null`.
Here's what is done there:
(`2>&1 > /dev/null` drops stdout and writes stderr to stdout—not what was meant. `which` doesn't write to stderr, so I drop that part.)That can be shortened significantly by using the return code directly in the if branch:
Or by just using the return code directly: And as it will return the return code of the last statement executed: