The reason why tar (or cpio) is recommended over cp for this procedure is because of how the tools operate.
cp operates on each file object in turn, reading it from disk and then writing it in its new location. Since the locations of the source and destination may not be close on the disk, this results in a lot of seeking between the locations.
tar and cpio read as much as possible in one go, and then write it into the archive. This means that the source files will be read one after another and the destination files will be written one after another (allowing for process switching, of course), resulting in much less seeking and hence less time taken.
Unfortunately there is no guarantee of anything being available.
However, most systems will have GNU coreutils. That alone provides about 105 commands. You can probably rely on those unless it's an embedded system, which might use BusyBox instead.
You can probably also rely on bash, cron, GNU findutils, GNU grep, gzip, iproute2, iputils, man-db, module-init-tools, net-tools, passwd (passwd or shadow), procps, tar, and util-linux.
Note that some programs might have some differences between distributions. For example /usr/bin/awk
might be gawk or mawk. /bin/sh
might be dash or bash in POSIX mode. On some older systems, /usr/bin/host
does not have the same syntax as the BIND version, so it might be better to use dig.
If you're looking for some standards, the Linux Standard Base defines some commonly found programs, but not all distributions claim to conform to the standard, and some only do so if you install an optional LSB compatibility package. As an example of this, some systems I've seen don't come with lsb_release
in a default install.
As well as this, the list of commands standardized by POSIX could be helpful.
Another approach to your problem is to package your script using each distribution's packaging tools (e.g. RPM for Red Hat, DEB for Debian, etc.) and declare a dependency on any other programs or packages you need. It's a bit of work, but it means users will see a friendlier error message, telling them not just what's missing, but what packages they need to install.
More info:
Best Answer
Others have already mentioned that
$#
is the number of command-line arguments, so I'll ignore that part of your question.Given
cmd1 && cmd2
, the shell first executescmd1
. Ifcmd1
fails, the entire expression fails. Ifcmd1
succeeds, the shell proceeds to executecmd2
. The entire expression succeeds if bothcmd1
andcmd2
succeed. So, the&&
operator is the short-circuiting boolean AND applied to shell commands. Uses of this operator can be replaced withGiven
cmd1 || cmd2
, the shell first executescmd1
. If it succeeds, the entire expression succeeds. Otherwise, the shell executescmd2
and the success or failure of the expression is determined bycmd2
. In short, this is the short-circuiting boolean OR applied to shell commands. You can replace this form withI've carefully used the phrases succeeded / succeeds and failed / fails above. Success, for shell commands, is defined as a process exit status of zero. Failure is any non-zero status. However, attempting to understand the
&&
and||
operators in terms of exit statuses is, at least to me, confusing since you end up with a weird sort of inverted logic.