Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash - creating tar for array items

Tags:

bash

shell

gzip

tar

I have an array with files and directories that I wish to add to the compressed tar (tar.gz). Originally I was planning to loop through the array and add each item to the tar, something like that:

tar czf my_app.tar.gz

for app_item in "${app_items[@]}"
do
    tar rzf my_app.tar.gz $app_item
done

Running the script I have found that I cannot add files to the compressed tar. I was wondering whether there is any other way of creating a tar from my list of location in the array.

Any help would be greatly appreciated!

like image 404
alexs333 Avatar asked May 27 '13 08:05

alexs333


2 Answers

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/null
for app_item in "${app_items[@]}"
do
    tar rf my_app.tar "$app_item"
done
gzip 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.

like image 174
Alfe Avatar answered Oct 15 '22 19:10

Alfe


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$$
done
tar cfz my_app.tar.gz -T items$$
rm items$$
like image 3
Mark Adler Avatar answered Oct 15 '22 20:10

Mark Adler