Skip to content

Latest commit

 

History

History
469 lines (419 loc) · 31 KB

filesystem.md

File metadata and controls

469 lines (419 loc) · 31 KB

Documentation for the functions in filesystem.sh. A general overview is given in the project documentation.

Quick access

Function documentation

If the pipes are not documented, the default is:

  • stdin: ignored
  • stdout: empty

Parameters enclosed in brackets [ ] are optional.

get_real_path()

The function processes the path $1 in 4 ways:

  • if it's a relative path, it's transformed to the absolute equivalent
  • symbolic file links are resolved, even if they are chained (i.e. a link pointing to a link pointing to a link etc.)
  • symbolic folder links are resolved using cd's -P flag
  • it cleans up ../ and ./ components

It works for files and folders with the restriction that they must exist. Use the string handling collection's get_absolute_path() for paths that don't exist.

Param.$1path to resolve and clean
Pipesstdoutif status is 0, the "real" path of $1, empty otherwise
Status 0success, "real" path written on stdout
1$1 doesn't exist

get_script_path()

Inspired by this StackOverflow(SO) answer. The function returns the full path including the filename and it's able to work in any call constellation: sourced, called in a subshell etc. It relies on $BASH_SOURCE which changes depending on the constellation, however, the element in this array with the highest index is always the path of the script executed initially.

Important: call this function as early as possible; before any directory changes in the script. The $BASH_SOURCE entry depends on the way the script is called and one of the possibilities is that the script is executed in a terminal using a relative filepath with respect to the shell's current directory; in that case the $BASH_SOURCE entry only contains that relative filepath and if the current directory changes, the output of this function is wrong.

Pipesstdout"real" absolute path (folder + file symlink resolved, cleaned) of the executed script
Status0

is_path_a()

Combined existence and type check. Example:

is_path_a "$path" "file" || echo "$path is not a file" && return
# do something with the file at $path...
Param. $1path
$2inode type: accepted values are folder, file or symlink
Status 0path $1 is of type $2
1path $1 is not of type $2
2path $1 doesn't exist
3$1 is empty
4$2 is empty
5$2 is unknown

is_readable()

Helpers to avoid read permission errors, with an optional additional internal is_path_a() type check. A typical use example is:

is_readable "$path" || echo "Path $path is not readable. Aborting..." && exit
Param. $1path
[$2]inode type: accepted values are folder, file or symlink. If the value is omitted or empty, no type check is performed.
Status 0path $1 is readable
1path $1 is not readable
2path $1 doesn't exist
3$1 doesn't have type $2
4$1 is empty
5$2 is unknown

is_writeable()

Helper to avoid write permission errors. Example:

is_writeable "$path" || echo "Path $path is not writeable. Aborting..." && exit

The function has a "check on existing path part" flag which configures the behavior for filepaths that don't exist on the system (yet). In these cases the answer whether a write will succeed or not depends on the type of operation and whether it requires the direct parent folder to exist or not. mkdir is a good example - let's imagine there's a empty directory /test where the user has write permission and wants to create the path /test/folder/subfolder:

  • mkdir /test/folder/subfolder will fail because /test/folder doesn't exist
  • mkdir -p /test/folder/subfolder works because the -p tells mkdir it's allowed to create multiple nested directories and since writing to /test is permitted, the operation is successful

This function is able to take this into account:

  • if the "check on existing path part" flag $2 is not raised it fails if the direct parent folder doesn't exist
  • if the flag is raised ($2 set to 1), it does what its name indicates: it walks up the path until it finds an existing directory and checks the write permission on that directory.

In the mkdir example above, is_writeable /test/folder/subfolder would return status 2 (= not writeable, parent missing); with the flag ($2 set to 1), that switches to status 0 (= writeable).

Param. $1path
[$2]"check on existing path part" flag - if the parent directory of $1 doesn't exist, it configures whether the function fails or if it walks up $1 until it finds an existing folder on which it checks the write permission - see explanations above
Status 0path $1 can be written
1there's no write permission on path $1
2the direct parent folder of path $1 doesn't exist (can only happen if $2 is omitted or set to 0)
3if $1 is empty

get_new_path_part()

Extracts the part of $1 which does not exist on the filesystem.

Param.$1path
Pipesstdoutpart of $1 which does not exist on the filesystem
Status0

get_existing_path_part()

Extracts the part of $1 which exists on the filesystem. Returns "at least" /

Param.$1path
Pipesstdoutpart of $1 which exists on the filesystem
Status0

try_filepath_deduction()

If there's only a single file (match) in the folder $1, returns its path

Param. $1path of the folder to search in
[$2]search pattern, if omitted, defaults to * (= everything)
Pipesstdoutif status is 0, the absolute filepath of the single match, empty otherwise
Status 0successful deduction, path is written on stdout
1folder $1 doesn't exist
2there's no match for $2 in $1
3there's more than 1 match for $2 in $1

create_folder()

mkdir wrapper with:

  • several checks before the actual creation attempt which allow to get specific status codes for any possible error type: if the path is empty (status 2), exists (3) or if the user has no write permission (4)
  • control over stdout and stderr: mkdir writes on stderr in case of failure. This function allows to be sure:
    • that stdout contains either nothing, the mkdir status code or stderr message, or a custom message, depending on the the stdout configuration $2
    • that stderr remains silent, even in case of mkdir failure
  • a system for the message customization: one template by status, with variable placeholders to inject the runtime parameters

Verbose mode / message customization:

The variable placeholders %path and %stderr_msg are replaced by the path $1 and the mkdir error message. Latter is only relevant if status is 1 (mkdir error), otherwise it should be empty. The default message templates are:

Status Template
0  folder %path created\n
1 %stderr_msg\n
2 folder creation error: no path provided\n
3 folder creation error: %path exists\n
4 folder creation error: no write permission for %path\n

%stderr_msg is empty if status is not 1.

create_folder "/new/folder/path" "verbose" prints folder /new/folder/path created\n in case of success. The messages can be customized by setting up an array variable where the indizes are the states and the values the corresponding templates (i.e. the success message template is at index 0, etc.). The name of the array variable - and not the variable itself - has to be provided as 3rd call parameter. It's perfectly valid to customize a subset of states/templates, the function falls back to the default templates where it can't find a customization. In the next example, the success message template is overwritten:

msg_defs[0]="custom message: folder %path created\n"
create_folder "new/folder/path" "verbose" "msg_defs"

prints custom message: folder /new/folder/path/ created\n if it's successful.

Examples:

  • stdout silent: create_folder "path/to/new/dir"
  • status code captured to variable: status=$(create_folder "/path/to/my_new_dir" "status")
  • mkdir error message captured to variable: error_msg=$(create_folder "/path/to/my_new_dir" "error_message")
Param. $1path
[$2]stdout configuration:
  • if omitted or an empty string, nothing is written on stdout
  • status or $?: status code
  • error_message or err_msg or stderr: mkdir call stderr output
  • verbose: status specific message, see explanations above
[$3]if $2 is set to verbose, the name of the array variable which contains the custom message templates - if omitted, the default templates are used; see explanations above
Pipesstdout
  • empty if $2 omitted or set to an empty string
  • the status returned by the mkdir call if $2 is set to status
  • eventual sterr output of the mkdir call if $2 is set to error_message
  • the status specific message if $2 is set to verbose
Status 0folder $1 created
1mkdir error, if $2 is set to error_message, stdout contains the content of mkdir's stderr output
2path $1 exists
3path $1 is not writeable
4$1 is empty

handle_cp_or_mv()

Internal handler for file/folder copy/move, used by the wrapper functions copy_file(), copy_folder(), move_file() and move_folder(). See their documentation for details.

Param. $1mode, possible values: copy, cp, move or mv
$2source path
$3destination path
[$4]stdout configuration:
  • if omitted or an empty string, nothing is written on stdout
  • status or $?: the status code
  • error_message or err_msg or stderr: mv/cp call stderr output
  • verbose: status specific message, see explanations in the wrapper functions
[$5]if $4 is set to verbose, the name of the array variable which contains the custom message templates - if omitted, the default templates are used, see exaplanation in the wrapper functions
Pipes and status are documented below for the wrapper functions. handle_cp_or_mv() has just one additional status which will never occur if the wrapper functions are used: status 7 to signal mode $1 is unknown

copy_file(), copy_folder(), move_file() and move_folder()

cp and mv wrapper with:

  • several checks before the actual copy/move attempt which allow to get specific status codes for any possible error type:
    • if the source path is empty (status 2), doesn't exist (3) or if the user has no read permission (4)
    • if the destination path exists (status 5) or if the user has no write permission (6)
  • control over stdout and stderr: mv and cp write on stderr in case of failure. The functions allows to be sure:
    • that stdout either contains nothing, the mv/cp status code or stderr message, or a custom message, depending on the the stdoutconfiguration $3
    • that stderr remains silent, even in case of mv/cp failure
  • a system for the message customization: one template by status, with variable placeholders to inject the runtime parameters

Verbose mode / message customization:

The templates support 4 variable placeholders:

  • %src: set to $2
  • %dest: set to $3
  • %stderr_msg: the stderr output of the mv or cp call. Only relevant for status 1.
  • %op: has the value move or copy

The default message templates are:

Status Template
0 - %src moved to %dest\n (for move/mv)
- %src copied to %dest\n (for copy/cp)
1 %stderr_msg\n
2 error: %op failed, source path empty\n
3 error: %op from %src to %dest failed because %src doesn't exist\n
4 error: %op from %src to %dest failed because there's no read permission on %src\n
5 error: %op from %src to %dest failed because %dest exists (won't overwrite)\n
6 error: %op from %src to %dest failed because there's no write permission on %dest\n

copy_file "/path/to/src" "path/to/dest" "verbose" prints /path/to/src copied to /path/to/dest\n in case of success. The messages can be customized by setting up an array variable where the indizes are the states and the values the corresponding templates (i.e. the success message template is at index 0, etc.). The name of the array variable - and not the variable itself - has to be provided as 4th call parameter. It's perfectly valid to customize a subset of states/templates, the function falls back to the default templates where it can't find a customization. In the next example, the success message template is overwritten:

msg_defs[0]="custom message: %source copied to %destination"
copy_file "/path/to/src" "/path/to/dest"  "verbose" "msg_defs"

prints custom message: /path/to/src copied to /path/to/dest if it's successful.

Examples:

  • stdout silent: move_file "path/to/src" "path/to/dest"
  • status code captured to variable: status=$(move_folder "/path/to/src" "/path/to/dest" "status")
  • cp error message captured to variable: err_msg=$(copy_file "/path/to/src" "/path/to/dest" "error_message")
Param. $1source path
$2destination path
[$3]stdout configuration:
  • if omitted or an empty string, nothing is written on stdout
  • status or $?: mv respectively cp call status code
  • error_message or err_msg or stderr: the mv respectively cp call stderr output
  • verbose: status specific message - see explanations above
[$4]if $3 is set to verbose, the name of the array variable which contains the custom message patterns. If omitted, the default message patterns are used; see explanations above
Pipesstdout
  • empty if $3 omitted or set to an empty string
  • the status returned by the mv/cp call if $3 is set to status
  • eventual sterr output of the mv/cp call if $3 is set to error_message
  • the status specific message if $3 is set to verbose
Status 0operation successful
1operation failure, if $3 is set to error_message (or its aliases), stdout contains mv's respectively cp's stderr output
2the source path $2 doesn't exist
3no read permission on source path $2
4the destination path $3 exists
5no write permission on destination path $3
6the source path $2 is empty
7the destination path $3 is empty

handle_rm()

Internal handler for file/folder removal, used by the wrapper functions remove_file(), remove_folder(), see their documentation for details.

Param. $1path
[$2] stdout configuration:
  • if omitted or an empty string, nothing is written on stdout
  • status or $?: rm call status code
  • error_message or err_msg or stderr: rm call stderr output
  • verbose: status specific message, see explanations in the wrapper functions
[$3]if $2 is set to verbose, the name of the array variable which contains the custom message patterns. If omitted, the default message patterns are used
Pipes and status are documented below for the wrapper functions.

remove_file() and remove_folder()

rm wrapper with:

  • several checks before the actual removal attempt which allow to get specific status codes for any possible error type: if the path is empty (status 2), doesn't exist (3) or if the user has no write permission (4)
  • control over stdout and stderr: rm writes on stderr in case of failure. This functions allows to be sure:
    • that stdout either contains nothing, the rm status code or stderr message, or a custom message, depending on the stdout configuration $2
    • that stderr remains silent, even in case of rm failure
  • a system for the message customization: one template by status, with variable placeholders to inject the runtime parameters

Verbose mode / message customization:

The variable placeholders %path and %stderr_msg are replaced by the path $1 and the mkdir error message. The default message templates are:

Status Template
0  %path removed\n
1 %stderr_msg\n
2 removal error: path is empty\n
3 removal error: %path doesn't exist\n
4 emoval error: no write permission on %path\n

%stderr_msg is empty if status is not 1.

remove_file "/path/to/remove" "verbose" prints /path/to/remove removed\n in case of success. The messages can be customized by setting up an array variable where the indizes are the states and the values the corresponding templates (i.e. the success message template is at index 0, etc.). The name of the array variable - and not the variable itself - has to be provided as 3rd call parameter. It's perfectly valid to customize a subset of states/templates, the function falls back to the default templates where it can't find a customization. In the next example, the success message template is overwritten:

msg_defs[0]="custom message: %path removed\n"
remove_folder "/path/to/remove" "verbose"  "msg_defs"

prints custom message: /path/to/remove removed if it's successful.

Examples:

  • stdout silent: remove_folder "path/to/new/dir"
  • status code captured to a variable: status=$(remove_file "/path/to/file_to_remove" "status")
  • rm error message captured to a variable:
err_msg=$(remove_folder "/path/to/my_new_dir" "error_message")
Param. $1path
[$2]stdout configuration:
  • if omitted or an empty string, nothing is printed on stdout
  • status / $?: mkdir status code
  • error_message / err_msg: / stderr mkdir call stderr output
  • verbose: for a status specific message, see explanations above
[$3]if $2 is set to verbose, the name of the array variable which contains the custom message templates - see explanations above
[$4]"return error if $1 doesn't exist" flag:
  • 1: the function returns with status 2 if $1 doesn't exist
  • omitted or any other value: the function returns with status 0 if $1 doesn't exist
Pipesstdout
  • empty if $2 omitted or set to an empty string
  • the rm status code if $2 is set to status or $?
  • eventual sterr output of the rm call, if $2 is set to error_message (or aliases)
  • the message if $2 is set to verbose
Status 0$1 removed or doesn't exist (if $4 is omitted or set to something else than 1)
1rm error, if $2 is set to error_message (or aliases), stdout contains the content of rm's stderr output
2path $1 is not writeable
3path $1 doesn't exist (only if $4 is set to 1)
4$1 is empty

load_configuration_file_value()

Bash allows to source (aka .) files which is a convenient way to load f.ex. configuration files, however, it has disadvantages as well:

  • the files have to comply with the bash syntax of course, f.ex. regarding comments, the way the variables are defined, etc.
  • the calling application has no control which variables are defined (or not), which ones are overwritten, etc.

It's sometimes easier and more flexible to load values with a file content search and extraction method like this function which is based on a search with grep and the extraction of the value using string processing utilities.

Variable definitions should have the assignment format:

<variable name>=<value>

Each definition has to be on a single line, with any number of whitespaces before the variable name, between the variable name and the assignment operator '=' or between the operator and the value. Inline comments are not allowed, they should be on their own lines. Examples of valid definitions:

cfg_filepath="/etc/test.conf"
I'm a comment
   cfg_filepath="/etc/test2.conf"
timeout     = 25

If the variable is enclosed in quotes (i.e. the quotes are loaded as part of the value) they are removed with the string handling collection's sanitize_variable_quotes()

Param. $1path of the configuration file
$2name of the variable to load
Pipesstdoutif status is 0, the loaded value, empty otherwise
Status 0successful, value is written on stdout
1file $1 doesn't exist
2path $1 is not a file
3no read permission on file $1
4no variable definition for the name $2
5$1 is empty
6$2 is empty