1

I have a list of files:

file_list=['test1.txt','test2.txt','test3.txt']

I want to find and copy these files to a destination folder. I have the following code:

for files in file_list:
    subprocess.call(["find", "test_folder/",
                    "-iname", files,
                    "-exec", "cp", "{}",
                    "dest_folder/",
                    "\;"])

But, i keep getting the error:

find: missing argument to `-exec

The shell command looks something like this:

$find test_folder/ -iname 'test1.txt' -exec cp {} dest_folder/ \;

Anything i am doing wrong?

msakya
  • 9,311
  • 5
  • 23
  • 31

2 Answers2

2

You don't need to escape the arguments; subprocess module calls find command directly without the shell. Replace "\;" with ";" and your command will work as is.

You could combine the search into a single command:

from subprocess import call

expr = [a for file in file_list for a in ['-iname', file, '-o']]
expr.pop() # remove last `-o`
rc = call(["find", "test_folder/", "("] + expr + [")", "-exec", 
           "cp", "-t", "dest_folder/", "--", "{}", "+"])

You could also combine expr list into a single -iregex argument if desired.

You don't need find command; you could implement the copying in pure Python using os.walk, re.match, and shutil.copy:

import os
import re
import shutil

found = re.compile('(?i)^(?:%s)$' % '|'.join(map(re.escape, file_list))).match
for root, dirs, files in os.walk('test_folder/'):
    for filename in files:
        if found(filename):
            shutil.copy(os.path.join(root, filename), "dest_folder/")
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • yeah you are right on the first one, I got it to working after an inherent bug not related to the code. Is latter option any better than former? Thanks! – msakya Mar 22 '14 at 16:15
  • 1
    @msakya: the single `find` command should be faster: it copies several files at a time. The pure Python solution should be more portable (it doesn't require `find`, `cp` commands). – jfs Mar 22 '14 at 16:43
1

You don't need to escape semi-colon. Here's what is working for me:

import shlex
import subprocess

file_list = ['test1.txt','test2.txt','test3.txt']

cmd = 'find test_folder -iname %s -exec cp {} dest_folder ;'
for files in file_list:
    subprocess.Popen(shlex.split(cmd % files))

Also see:

Hope that helps.

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • I dont get any error now, but the destination folder doesnt have the copied files. Is there a way to look at whats being run? :) – msakya Mar 22 '14 at 02:34
  • I dont get any error now, but the destination folder doesnt have the copied files. Is there a way to print the subprocess being run? :) – msakya Mar 22 '14 at 02:40
  • @msakya hm, it's working for me. You may find the way to log the commands here: http://stackoverflow.com/questions/14836947/output-the-command-line-called-by-subprocess – alecxe Mar 22 '14 at 02:47
  • @msakya does adding `shell=True` argument to `Popen` make any difference? – alecxe Mar 22 '14 at 02:48
  • This is weird, I am not really sure whats going on. putting `shell=True` didnt help. – msakya Mar 22 '14 at 03:14
  • @msakya by the way, I've modified the code a bit (using `shlex` now). – alecxe Mar 22 '14 at 03:15
  • I rewrote the function as per your rewrite, `def findcopy(full_path, list_of_files, dest_folder): """ """ import subprocess import shlex cmd = 'find %s -iname %s -exec cp {} %s ;' for gen_files in list_of_files: subprocess.Popen(shlex.split(cmd % (full_path, gen_files, dest_folder)))` but it still gives me no copied files. Does it have to do with supplying `dest_folder` as a variable too. – msakya Mar 22 '14 at 03:19
  • @msakya nope. Are you sure you have these `txt` files inside `test_folder`? – alecxe Mar 22 '14 at 03:51
  • yes they are. I just ran `find` independently from shell and it works. – msakya Mar 22 '14 at 04:07
  • I apologize. I found the bug in the code. Your first answer worked all along. Again, sorry. – msakya Mar 22 '14 at 04:22
  • you should call `shlex.quote(filename)`, to support filename with spaces – jfs Mar 22 '14 at 06:25