Home / Alt manpages / install(1)

  • install(1)
  • User command
  • linux

Install Files Safely with GNU install

You will finish with a repeatable way to copy a file into place, create its destination directories, set its mode, and keep a backup before replacing an existing file. The examples use GNU install from coreutils 9.4, installed here as package version 9.4-3ubuntu6.3.

Allow about fifteen minutes. You need a shell and a source file you are willing to copy. The examples use /tmp so they do not need elevated privileges. Installing into locations such as /usr/local/bin normally needs sudo; changing a system file can affect services and other users.

1. Check the version and the command shape

Start with read-only checks. This avoids reaching for a flag from a different implementation of install and confirms which binary your shell will run:

$ install --version
install (GNU coreutils) 9.4
$ command -v install
/usr/bin/install

The common forms are install SOURCE DEST, install SOURCE... DIRECTORY, install -t DIRECTORY SOURCE..., and install -d DIRECTORY.... GNU install is for putting files in known locations. It is not a package manager, and it does not resolve dependencies.

2. Copy one file with an explicit mode

Make a small staging area and copy a file into it. Replace the source path with your own readable file when you use this pattern:

$ mkdir -p /tmp/install-demo/source /tmp/install-demo/dest
$ printf '%s\n' 'release 1' > /tmp/install-demo/source/tool.txt
$ install -v -m 0640 /tmp/install-demo/source/tool.txt /tmp/install-demo/dest/tool.txt
'/tmp/install-demo/source/tool.txt' -> '/tmp/install-demo/dest/tool.txt'
$ stat -c 'mode=%a owner=%U group=%G' /tmp/install-demo/dest/tool.txt
mode=640 owner=andy group=dixon

-m 0640 sets the destination mode in the same style as chmod. The leading zero makes the octal intent clear: the owner can read and write, the group can read, and others have no access. -v prints what was created or copied. It is useful during a first run and can be omitted in scripts that do not need that output.

Without -m, this GNU version uses rwxr-xr-x as the mode setting described by its manual, subject to the process umask. Do not rely on that default for a secret, credential, private key, or other file where permissions are part of the security boundary. Specify the mode deliberately.

Checkpoint

The destination exists, contains the source text, and stat reports mode 640. If it does not, check the source path and the permissions on each parent directory before trying sudo.

3. Create a destination tree and install a program

Use -D when the final destination's parent directories may not exist. It creates the leading components and then copies the source to the final path:

$ printf '%s\n' '#!/bin/sh' 'printf "%s\n" ready' > /tmp/install-demo/source/ready
$ install -D -m 0755 /tmp/install-demo/source/ready /tmp/install-demo/dest/bin/ready
$ /tmp/install-demo/dest/bin/ready
ready
$ stat -c 'mode=%a path=%n' /tmp/install-demo/dest/bin/ready
mode=755 path=/tmp/install-demo/dest/bin/ready

This is handy for a hand-built binary or a small script. A mode of 0755 makes it executable by the owner, group, and others. Do not use it automatically for data files. If a destination already exists, this operation replaces it, so inspect the path before running it when the file matters.

To undo this example, remove only the demo tree after checking its exact path:

$ rm -rf -- /tmp/install-demo

That removal is destructive. Never adapt the command by replacing the explicit temporary path with a broad directory or a variable you have not inspected.

4. Install several files into an existing directory

For several sources, the final argument must already be a directory. The target-directory form makes that boundary explicit:

$ mkdir -p /tmp/install-demo/dest/bin
$ printf '%s\n' 'first' > /tmp/install-demo/source/first.txt
$ printf '%s\n' 'second' > /tmp/install-demo/source/second.txt
$ install -m 0644 -t /tmp/install-demo/dest/bin \
    /tmp/install-demo/source/first.txt /tmp/install-demo/source/second.txt
$ find /tmp/install-demo/dest/bin -maxdepth 1 -type f -printf '%f\n' | sort
first.txt
second.txt

-t is useful when a command builds the source list programmatically, because the directory is named before the sources. The directory must exist; use -D for a single file when you also need missing parent directories.

5. Avoid an unnecessary replacement with compare mode

-C compares the source and destination. If content, ownership, and permissions already match, GNU install leaves the destination untouched:

$ install -C -m 0640 /tmp/install-demo/source/tool.txt /tmp/install-demo/dest/tool.txt
$ printf 'exit status: %s\n' "$?"
exit status: 0

This is useful for deployment steps where an unchanged file should keep its existing metadata and avoid needless writes. A changed source is still copied, and the requested mode is applied. Verify with stat or a checksum when the distinction matters.

6. Keep a backup before replacing a file

Replacement is the point where a typo can destroy the previous working version. Add --backup when you want GNU install to preserve the existing destination, and use -S for an obvious suffix:

$ printf '%s\n' 'release 2' > /tmp/install-demo/source/tool.txt
$ install --backup=simple -S .old /tmp/install-demo/source/tool.txt /tmp/install-demo/dest/tool.txt
$ printf 'new: %s\n' "$(cat /tmp/install-demo/dest/tool.txt)"
new: release 2
$ printf 'old: %s\n' "$(cat /tmp/install-demo/dest/tool.txt.old)"
old: release 1

The default backup suffix is ~; -S .old makes the resulting name easier to spot. The backup is not a version-control system, and repeated replacements can overwrite the same simple backup. For a numbered history, use --backup=numbered and inspect the names produced before automating cleanup.

Recovery is a normal file replacement: stop the deployment, check the backup contents, then install the backup back over the destination with the intended mode. Do not restore blindly if the destination is a live executable or service configuration.

7. Use elevated privileges only at the final boundary

For a system-wide installation, prepare and inspect the source as your ordinary user, then elevate only the copy operation:

$ command -v my-tool
/home/andy/bin/my-tool
$ install -D -m 0755 /home/andy/bin/my-tool /usr/local/bin/my-tool
install: cannot create regular file '/usr/local/bin/my-tool': Permission denied
$ sudo install -D -m 0755 /home/andy/bin/my-tool /usr/local/bin/my-tool

The first command is ordinary. The second changes a system location and usually needs sudo. Before running it, confirm the source path, destination path, mode, and ownership requirements. If the destination is a service executable, arrange a rollback and a service restart plan separately; install does not reload a daemon.

Done means

  • You confirmed GNU coreutils 9.4 and the path of install.
  • The destination has an explicit mode appropriate for its contents.
  • You used -D only where creating missing parent directories was intended.
  • You used -C when avoiding unchanged replacements mattered.
  • You used a backup before replacing a file that needed recovery.
  • You kept sudo for the final system-location change and checked the exact paths first.