Bash Index : 'set*' - The 'set*' Bash commands : description, flags and examples

mail

setcap

Usage

Set file capabilities
Heard of it in this very interesting article.
mail

setfacl

Installed with the Debian package

acl

Usage

Set or modify file ACL. This allows granting specific rights to specific users / groups on specific files, without setting global permissions. For instance, if Bob's home directory is :
drwx------ 64 bob developers 4,0K jan. 15 20:38 bob/
and we would like Alice to have read access to /home/bob/, we can :

Command syntax :

setfacl -m aclEntry someFile
with aclEntry made of prefix:userOrGroup:permissions
  • prefix :
    • u: to change user rights
    • g: to change group rights
    • o: to change other rights. No need to specify userOrGroup
    • d:u: to declare default user rights
    • d:g: to declare default group rights
    • d:o: to declare default other rights
  • permissions : specified either numerically or with symbols (like in chmod) :
    • r : read permission
    • w : write permission
    • x : execute permission
    • X : execute permission, if the file is a directory or already has execute permission for some user (details)
    • - : ignored, rx is equivalent to r-x

Flags

Flag Usage
-b --remove-all
  • remove all extended ACL entries
  • the base ACL entries of the owner, group and others (i.e. Linux permissions) are retained
-d --default All operations apply to the default ACL
-m modify an existing ACL entry
-R Recursive : apply rights to all files and directories. -R must be supplied before -m : -Rm
-x remove an ACL entry :
setfacl -x u:kevin someFile

Example

Grant rw rights to a user on a single file :

setfacl -m u:alice:rw- file

Grant rw rights to a user on all files of a directory :

setfacl -Rm u:alice:rw- directory

Set default rights so that new files will inherit them (details) :

setfacl -m d:u:alice:rw directory/

Grant access to a file tree (source) :

setfacl -R -m user:stuart:rwX path/to/base/directory

If it complains : setfacl: Option -m: Invalid argument near character n :

setfacl -R -m user:httpd:rwx /data
setfacl: Option -m: Invalid argument near character 6
What's wrong ?
  1. Which is the 6th character ? It's the 6th of the value passed to -m :
    user:httpd:rwx
    123456
    Something's wrong with the username
  2. Does this username exist ? None of the commands above return a result : there is no such httpd user.
mail

set

Usage

Toggle options within a script. At the point in the script where you want the options to take effect, use set -o optionName or, in short form : set -shortOption. These two forms are equivalent.
To disable an option : set +o optionName, or set +shortOption.

Flags

optionName shortOption Usage
noexec n read commands but do not execute them (syntax check)
errexit e abort script at first error : when a command exits with non-zero status, except in these constructs : See notes and examples, Discussion about -e.
nounset u leave script and display an error message when using an unset variable
pipefail
  • By default, pipelines only return a failure if the last command errors.
  • If pipefail is set, the return value of a pipeline is :
    • the value of the last (rightmost) command to exit with a non-zero status
    • or zero if all commands in the pipeline exit successfully
  • When used in combination with -e, pipefail will make a script exit if any command in a pipeline errors.
verbose v print each command to stdout before executing it
xtrace x like verbose, but expands commands
(full list)

Discussion about -e :

-e is often presented as a mandatory flag that should be used in all scripts. But it's also considered by others as a bad / useless practice (details : 1, 2) because :
  • it's not an error when a test (if, [ ], ) evaluates to false :
    • dealing with a false status is what tests are for
    • treating a false as an error and exiting unconditionally is an over-reaction which brings nothing to the safety scripts
  • exceptions have been added to -e to workaround the false positives, but these exceptions
    • are not consistent across Bash versions
    • vary whether the process is/is not a subshell
    which actually adds complexity with no gain on safety

Example

Notes and examples with -e (details) :

This doesn't work on :
  • commands within if, until, while block
  • compound commands (list using && or ||)
  • commands with return value being inverted via !
set -e; echo -n 'hello'; true; echo ' world'
Outputs : hello world
echo "set -e; echo -n 'hello'; false; echo ' world'" | bash
Outputs : hello (the echo | bash hack is just to be able to see the result, since because of the false, an exit is executed, forcing to leave the current shell)
set -e; dir='/tmp'; if [ -d "$dir" ] ; then echo "$dir exists"; else echo "$dir does not exist"; fi
Outputs : /tmp exists
No non-success exit code met, -e keeps sleeping.
set -e; dir='/aDirThatDoesNotExist'; if [ -d "$dir" ] ; then echo "$dir exists"; else echo "$dir does not exist"; fi
Outputs : /aDirThatDoesNotExist does not exist
A non-success exit code is met, but -e is muzzled by if.
set -e; dir='/tmp'; [ -d "$dir" ] && echo "$dir exists" || echo "$dir does not exist"
Outputs : /tmp exists
No non-success exit code met, -e keeps sleeping.
set -e; dir='/aDirThatDoesNotExist'; [ -d "$dir" ] && echo "$dir exists" || echo "$dir does not exist"
Outputs : /aDirThatDoesNotExist does not exist
A non-success exit code is met, but -e is muzzled by ????.
#!/usr/bin/env bash
set -e
echo -n 'hello'
true
echo ' world'
Outputs : hello world
#!/usr/bin/env bash
set -e
echo -n 'hello'
false
echo ' world'
Outputs : hello, and returns the exit code 1
#!/usr/bin/env bash
set -e
echo -n 'hello'
if true; then
	echo -n ' wonderful'
fi
echo ' world'
Outputs : hello wonderful world
#!/usr/bin/env bash
set -e
echo -n 'hello'
if false; then
	echo -n ' wonderful'
fi
echo ' world'
Outputs : hello world, and returns the exit code 0.
A non-success exit code is met, but -e is muzzled by if.

Opportunity for a joke :

If you run set -e in a terminal, this will affect the current shell and any further command your "victim" will type. At the 1st non-success return code met (which is VERY easy : try TAB-completing like cd TAB), an exit will be fired, closing the terminal

If you _unintentionally_ run that joke on yourself (), you can disable the -e flag with : set +e

Hack that simulates sending parameters to a script :

  1. set -- whatever
    This construct actually turns whatever into positional parameters. whatever can be :
    • a list of files : file1 file2 file3
    • a shell expansion corresponding to a list of files : /path/to/*jpg
    • the result of a command : $(ls -1)
  2. You can then "read" these as if they were previously sent as parameters :
    set -- $(ls -1); echo $1 $2 $3
    file1 file2 file3		3 files of the current directory
    set -- $(ls -1); echo $@
    ... ... ... ...		all of them