Well, it turns out, there's a lot more that a command that copies files can do, and by learning this one weird command, you can save a lot of typing and express, in one command, ideas that would normally take several.
Your first, and perhaps only, encounter with the
install tool (unless you're a
package maintainer) is likely when following installation instructions for
single binary software distributions.
Let's say we want to install
kubectl. We've chosen the single binary
installation path to get it onto our machine:
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
$ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 138 100 138 0 0 916 0 --:--:-- --:--:-- --:--:-- 920 100 45.8M 100 45.8M 0 0 17.6M 0 0:00:02 0:00:02 --:--:-- 20.8M
So how do I get the binary installed? The first guess would be to use the
sudo cp -f kubectl /usr/local/bin/
But there's also the
sudo install kubectl /usr/local/bin/
At this point, using
install feels identical to
cp, but bear with me,
because it gets better.
Often, when adding things to a filesystem, you want them to be owned by a
specific user. Usually this is
root, but it could be another login user, a
system user, or something weird like
A first attempt to set the owner would probably be:
sudo cp -f kubectl /usr/local/bin/ sudo chown root:root /usr/local/bin/kubectl
But did you know you can use
install can take the place of
chown with the
sudo install -o root -g root kubectl /usr/local/bin/
By default, the above will assign the user or group of the parent process. That
means, in many cases, no extra flags are even needed to get the behavior you
want. That means our
install command can be simplied to the following:
sudo install kubectl /usr/local/bin/
One line instead of two? Not bad, not bad. But
install does more than that.
Another common task when installing things is setting file permissions. You want your binaries to be executable, right? Maybe not by everyone, but by some people? Or maybe you are copying a text file and want for it to decidedly not be executable, hmm?
To achieve this, let's add
chmod to our previous non-
sudo cp -f kubectl /usr/local/bin/ sudo chown root:root /usr/local/bin/kubectl sudo chmod 0755 /usr/local/bin/kubectl
Well, guess what?
install has an app for that. It can take the place of
chmod with the
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/
install sets the file permissions to
0755, which means that it's
readable/executable by everyone, but writable only by the owner. For executable
commands, this is almost always what you want, so for the most common case, no
arguments are needed, and the command can be reduced to:
sudo install kubectl /usr/local/bin/
Now it's one line instead of three. But, again, we're not done yet.
Up until now, we've been installing into
/usr/local/bin/, which pretty much
always exists. But maybe we want to do something different, like build a root
filesystem or Debian package, and we need to build up the directory structure as
part of our installation.
Say we want to install
/opt/custom/path/to/kubectl instead of our
usual location. If you were to use
mkdir, you'd need to first create
/opt/custom/path/, and then
sudo mkdir /opt/custom/ sudo mkdir /opt/custom/path/ sudo mkdir /opt/custom/path/to/
To avoid doing all that, you can add the
--parents flag to auto-create
sudo mkdir -p /opt/custom/path/to/
So now your complete non-
install command looks something like this:
sudo mkdir -p /opt/custom/path/to/ sudo cp -f kubectl /opt/custom/path/to/ sudo chown root:root /opt/custom/path/to/kubectl sudo chmod 0755 /opt/custom/path/to/kubectl
install, on the other hand, offers the
-D option, which behaves just like
mkdir -p command above, ensuring
kubectl has a place to go. With
install, our command becomes the following:
sudo install -D kubectl /opt/custom/path/to/kubectl
Four lines reduced to just one. But that's still not all that
install can do.
Sometimes, especially on a personal workstation, you might want to keep the old
version of a file around for a little while. Maybe you're upgrading your
kubectl binary, but aren't quite sure if the new one will work with your
You might create a little backup of the file first. Let's add the following to
our previous non-
sudo mkdir -p /opt/custom/path/to/ sudo cp -f /opt/custom/path/to/kubectl /opt/custom/path/to/kubectl~ sudo cp -f kubectl /opt/custom/path/to/ sudo chown root:root /opt/custom/path/to/kubectl sudo chmod 0755 /opt/custom/path/to/kubectl
install command, you can use the
-b flag, which is much less
sudo install -b -D kubectl /opt/custom/path/to/kubectl
install supports stripping debug symbols from executables with the
--strip flag. This is often useful when building from source or preparing an
executable for distribution.
Let's assume for the moment that
kubectl still has debug symbols (even though
it doesn't). Our non-
install command adds the
sudo mkdir -p /opt/custom/path/to/ sudo cp -f /opt/custom/path/to/kubectl /opt/custom/path/to/kubectl~ sudo cp -f kubectl /opt/custom/path/to/ sudo chown root:root /opt/custom/path/to/kubectl sudo chmod 0755 /opt/custom/path/to/kubectl sudo strip /opt/custom/path/to/kubectl
This is getting really unwieldy, but with
install, we just add
sudo install -s -b -D kubectl /opt/custom/path/to/kubectl
Idempotence is a fancy way of saying that no matter how many times an action is performed, the result will be the same as if the action had been performed only once.
--compare flag checks file content, ownership, and
permissions. If none of these things have changed,
install will not modify the
target file at all.
This is great! This means you can run your install script as many times as you like and still get the same result.
I don't even want to try the non-
install version, but since you've read this
far, I'd feel bad if I didn't try. Here goes nothing:
# install.sh if [ -e /opt/custom/path/to/kubectl ] ; then cmp kubectl /opt/custom/path/to/kubectl if [ $? -ne 0 ] ; then sudo mkdir -p /opt/custom/path/to/ sudo cp -f /opt/custom/path/to/kubectl /opt/custom/path/to/kubectl~ sudo cp -f kubectl /opt/custom/path/to/ sudo chown root:root /opt/custom/path/to/kubectl sudo chmod 0755 /opt/custom/path/to/kubectl sudo strip /opt/custom/path/to/kubectl fi fi
Wow, that's awful! It definitely works, but this is an awful bit of logic to lug around.
install, we can turn on idempotent behavior with
-c, and our command
sudo install -c -s -b -D kubectl /opt/custom/path/to/kubectl
When all is said and done, this one-liner replaces the entire script I wrote above, and does exactly the same thing, probably faster, and way less prone to typing errors.
install command is a fine example of a convenience function. It provides a
terse, easy-to-understand one-liner that is also self-documenting.
install instead of the equivalent individual commands makes the intent
of your installation script very clear, and achieve more precise results with
And the best part?
install is always there. Even in a stripped down
busybox userland, you can expect to find
it, because it's part of coreutils.
So have fun, use it wherever you like, and be one of the cool people who knows
about the ultra-convenient, specialized relative of
cp known as