Bash - creating tar for array items Bash - creating tar for array items shell shell

Bash - creating tar for array items


The problem only exists with compressed archives. I propose to create and use an uncompressed archive first and compress it later when the loop has been run through.

tar cf my_app.tar --files-from /dev/nullfor app_item in "${app_items[@]}"do    tar rf my_app.tar "$app_item"donegzip my_app.tar

As @Matthias pointed out in a comment, creating an empty archive (what we want in the first line) is typically refused by tar. To force it to do this, we need a trick which differs from operating system to operating system:

  • BSD: tar cf empty.tar --from-file /dev/null
  • GNU (Linux): tar cvf empty.tar --files-from /dev/null
  • Solaris: tar cvf empty.tar -I /dev/null

More details about this explains the page he linked to.

A completely different approach which also seems to work nicely with file names with spaces in them (but not with file names with newlines in them, so it is not quite as general):

tar cfz my_app.tgz --files-from <(printf "%s\n" "${app_items[@]}")

And yet another way of doing this (which also works with newlines and other stuff in the file names):

eval tar cfz my_app.tgz $(printf "%q " "${app_items[@]}")

But as usual with eval you should know what you pass to it and that nothing of this comes from an untrusted source, otherwise it might pose a security issue, so in general I recommend to avoid it.


Make a file with the names in the array, and then use the -T option of tar (BSD or GNU) to read that file. This will work for any number of files, will work with files with spaces in the names, and will compress while archiving to minimize required disk space. E.g.:

for (( i = 0;  i < ${#app_items[@]}; i++))do  echo ${app_items[$i]} >> items$$donetar cfz my_app.tar.gz -T items$$rm items$$