I am writing a script to zip up old files and in examples online I found the below. I would like to know in detail what "${files[@]}" does or how to read the special characters. "${files[@]}"

files=($(find /var/cdrs -maxdepth 1 -name \*.C*R -mtime +150))
tar cvfz /var/cdrs_backup/CDRBackup_$(date +%Y%m%d_%H%M%S).tar.gz "${files[@]}"
  • It's the array (and array syntax) in some shells like bash, ksh, zsh, mksh – cuonglm Aug 30 '16 at 19:19

In short, you create a files array and expands it.

You read it like this:

VAR=... means you are assigning a variable. VAR=(...) means you are assigning a bash array to a variable.

$(...) means you are running a command and capturing its output, in your case the list of files that match the given pattern that are so old and then assigning each file to an element in a bash array.

${...} signifies that you are reading the value of a variable, for example:

$ SOMEVAR="a value"
$ echo "${SOMEVAR}"
a value

In bash $VAR and ${VAR} are equivalent, but the ${VAR} notation allows you to do some extra things. Most notably echo "${VAR}iable" will expand the $VAR variable and concat it with the iable string whereas echo $VARiable will try to expand the $VARiable variable. You can also do some advanced substitution using the ${...} notation.

In our case we are reading the file variable with ${file...}. Next, the [...] indicates that we are reading a bash array. So we are trying to access an element of the files array, the bit inside the [...] tells us which elements, this can be 1 to access the first element, 2 to access the second and so on (bash arrays are indexed from 1 not 0). @ means all elements, so we are trying to access all elements of the bash array called file.

You can try it out with the following:

% ARRAY=("a value" "another value" "fred")
% for x in "${ARRAY[@]}"; do echo "$x"; done
a value
another value

The advantage to using arrays over just space separated strings is you can include spaces in the values, like above. So in your case each file in the files array will be treated as a separate argument and spaces in the file names will be handled correctly.

So in essence your snipit finds and collects a list of files and passes them as individual arguments to the tar command.


The files=(...) creates an array of filenames

The syntax "${files[@]}" means _every element of the array; ie every filename found. Note the "..." surround it is important to stop some filenames being split up.

(This may fail if any filename has a carriage-return in it).


files=(...) creates an array of strings on ksh, which created this syntax, and on shells that adopted it later like bash and others.

$(find /var/cdrs -maxdepth 1 -name \*.C*R -mtime +150) creates a space separated list of pathnames matching the specified conditions. However, if a filename contains one of the IFS characters, typically space, tab and linefeed, the filename will be split in pieces and then be incorrectly stored in the array.

"${files[@]}" is expanded to a list of strings where each element is quoted. Quoting the elements is useless here as the array cannot contain spaces, tabs or carriage returns anyway as stated in the previous paragraph. This syntax can then be slightly simplified here by ${files[*]}.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.