2

I want to collect all the files I have used in a project. I am using find command, and I want it to find a list of files and then I pass its result to zip command to create a single zip file containing all the matched files. Just a convenience if it is possible. However, it seems there are problems with it and it does not work.

find /lmms/samples/ -name warp01*,JR_effect2k*,clean_low_key*,q_kick_2*,sticky_q_kick*,upright_bass*,pizzi*,chorded_perc*,Tr77_kick*,Tr77_tom1*,Tr77_cym*,hihat_008a*,Hat_o.ds,Hat_c.ds,Kickhard.ds,Tr77_snare* -exec zip {} ~/Desktop/files.zip

Output is:

find: missing argument to `-exec'

PS.

After fixing some errors pointed out in the below answers and following their guidelines, I have reformatted the code as below:

find ~/lmms/samples/ (-name warp01* -o -name JR_effect2k* -or -name clean_low_key* -or -name q_kick_2* -or -name sticky_q_kick* -or -name upright_bass*-or  -name pizzi* -or -name chorded_perc* -or -name Tr77_kick* -or -name Tr77_tom1* -or -name Tr77_cym* -or -name hihat_008a* -or -name Hat_o.ds -or -name Hat_c.ds -or -name Kickhard.ds -or  -name Tr77_snare*)  -exec zip -add  ~/Desktop/files.zip {} +

It still fails with the message bash: syntax error near unexpected token(' `

Removing the parentheses eliminates error but does seem to only add one file to the archive, which surprisingly, I do not seem to find on my Desktop!!!

 find ~/lmms/samples/ -name warp01* -o -name JR_effect2k* -or -name clean_low_key* -or -name q_kick_2* -or -name sticky_q_kick* -or -name upright_bass*-or  -name pizzi* -or -name chorded_perc* -or -name Tr77_kick* -or -name Tr77_tom1* -or -name Tr77_cym* -or -name hihat_008a* -or -name Hat_o.ds -or -name Hat_c.ds -or -name Kickhard.ds -or  -name Tr77_snare*  -exec zip  ~/Desktop/files.zip {} +
  adding: home/john/lmms/samples/drumsynth/tr77/Tr77_snare.ds (deflated 49%)
  • 1
    Following your PS: there still remain several errors in your find command (proper spacing and pattern quoting). I have updated my answer to add a zip-only command. – xhienne Jan 12 '17 at 13:16
  • You need to quote the patterns as StephenKitt showed you in his answer: -name "file*", not just -name file* – xhienne Jan 12 '17 at 13:39
  • I think It actually worked without quoting after I escaped the parentheses. – codezombie Jan 12 '17 at 13:48
  • 1
    Sometimes it will work, sometimes not, and you probably won't notice it. You are free to not follow Stephen's syntax of course. – xhienne Jan 12 '17 at 13:52
  • 1
    Every pattern (i.e. filename containing *, ? or [...]) should be surrounded be single or double quotes: -name clean_low_key* => -name 'clean_low_key*' or -name "clean_low_key*". See the note in my answer. If you want a clear demonstration of why it matters, do shopt -s nullglob and try your command (then undo this with shopt -u nullglob) – xhienne Jan 12 '17 at 14:06
8

-exec takes two parameters: the command to execute, and a flag to tell find whether the command should be run once per match (;) or with as many files as possible per run (+).

In addition, the zip parameters are the wrong way round.

The -name test doesn't work that way either; it only takes one pattern at a time. If you want to check for multiple patterns, you need to use multiple -name tests combined using -o ("or"), and wrap them in parentheses (thanks to xhienne for pointing that out):

find /lmms/samples/ \( -name "warp01*" -o -name "JR_effect2k*" ... \) -exec ...

(quoting each pattern to avoid issues with shell globbing).

All in all, if you fix your name tests and end your find with

-exec zip ~/Desktop/files.zip {} +

it should do the right thing.

  • Thanks @StephenKitt it seems to work now. Files have been added to ~/Desktop/files.zip, but in hierarchical order. I mean their directories have been added as well. Here is the created zip if you mind checking it out. s9.picofile.com/file/8282171700/files.zip.html – codezombie Jan 12 '17 at 12:59
  • 2
    If you don't want to store the paths, you can use zip's -j option to drop them. You need to be sure that you don't have two (or more) files with the same name in different directories! – Stephen Kitt Jan 12 '17 at 13:08
5

You just need to terminate your -exec option with either a ; or a + (man find). Your zip file must precede the files you put in your archive IIRC, so this would become:

find ... -exec zip ~/Desktop/files.zip {} ;
find ... -exec zip ~/Desktop/files.zip {} +

The + version aggregates the parameters at the end of the zip command and calls one zip for all the files (or several zip if your commands are really long). It's less I/O intensive but the downside is that you can only use {} once and at the end, just before the +. The ; version is more flexible but calls zip for each file.

Alternate solution without find

You also have a problem with the -name predicate and @StephenKitt gives you the correct syntax.

Here is another syntax that uses zip's ability to understand globbing patterns like file*. Therefore it doesn't use find, is closer to your original proposal, and probably less error-prone for someone not used to find:

$ zip -r  ~/Desktop/files.zip /lmms/samples/ --include 'warp01*' 'JR_effect2k*' 'clean_low_key*' 'q_kick_2*' 'sticky_q_kick*' 'upright_bass*' 'pizzi*' 'chorded_perc*' 'Tr77_kick*' 'Tr77_tom1*' 'Tr77_cym*' 'hihat_008a*' 'Hat_o.ds' 'Hat_c.ds' 'Kickhard.ds' 'Tr77_snare*'

Note: patterns are separated by space. The quotes around them are mandatory, else the patterns may be interpreted by your shell, not by zip.

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.