让 python 等到 subprocess.call 完成它的命令
Making python wait until subprocess.call has finished its command
所以这个问题是 this 的后续问题(阅读评论以及我采取的路径)。我只希望第一个调用 robocopy 在继续执行其余代码之前完成执行。因为我希望第二个 robocopy 跳过所有文件,因为它们已经被复制了。然而,正在发生的事情是脚本的其余部分将 运行 (即启动第二个 robocopy),而第一个 robocopy 正在复制文件。下面是代码:
call(["start", "cmd", "/K", "RoboCopy.exe", f"{self.srcEntry.get()}", f"{self.dstEntry.get()}", "*.*", "/E", "/Z", "/MT:8"], stdout=PIPE, shell=True)
temp2 = Popen(["RoboCopy.exe", f"{self.srcEntry.get()}", f"{self.dstEntry.get()}", "*.*", "/E", "/Z"], stdout=PIPE, stdin=PIPE, shell=True)
编辑 1:
复制大文件时问题很明显。我正在考虑加入一个睡眠功能,该功能取决于要复制的文件的总大小。但是,这没有考虑 upload/download 速度,因为文件将通过网络传输。
我使用以下函数启动我的命令,该命令等待操作完成,但有一个超时:
import os
import logging
logger = logging.getLogger()
def command_runner(command, valid_exit_codes=None, timeout=30, shell=False, decoder='utf-8'):
"""
command_runner 2019103101
Whenever we can, we need to avoid shell=True in order to preseve better security
Runs system command, returns exit code and stdout/stderr output, and logs output on error
valid_exit_codes is a list of codes that don't trigger an error
"""
try:
# universal_newlines=True makes netstat command fail under windows
# timeout does not work under Python 2.7 with subprocess32 < 3.5
# decoder may be unicode_escape for dos commands or utf-8 for powershell
if sys.version_info >= (3, 0):
output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell,
timeout=timeout, universal_newlines=False)
else:
output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell,
universal_newlines=False)
output = output.decode(decoder, errors='backslashreplace')
except subprocess.CalledProcessError as exc:
exit_code = exc.returncode
# noinspection PyBroadException
try:
output = exc.output
try:
output = output.decode(decoder, errors='backslashreplace')
except Exception as subexc:
logger.debug(subexc, exc_info=True)
logger.debug('Cannot properly decode error. Text is %s' % output)
except Exception:
output = "command_runner: Could not obtain output from command."
if exit_code in valid_exit_codes if valid_exit_codes is not None else [0]:
logger.debug('Command [%s] returned with exit code [%s]. Command output was:' % (command, exit_code))
if output:
logger.debug(output)
return exc.returncode, output
else:
logger.error('Command [%s] failed with exit code [%s]. Command output was:' %
(command, exc.returncode))
logger.error(output)
return exc.returncode, output
# OSError if not a valid executable
except OSError as exc:
logger.error('Command [%s] faild because of OS [%s].' % (command, exc))
return None, exc
except subprocess.TimeoutExpired:
logger.error('Timeout [%s seconds] expired for command [%s] execution.' % (timeout, command))
return None, 'Timeout of %s seconds expired.' % timeout
except Exception as exc:
logger.error('Command [%s] failed for unknown reasons [%s].' % (command, exc))
logger.debug('Error:', exc_info=True)
return None, exc
else:
logger.debug('Command [%s] returned with exit code [0]. Command output was:' % command)
if output:
logger.debug(output)
return 0, output
# YOUR CODE HERE
executable = os.path.join(os.environ['SYSTEMROOT'], 'system32', 'robocopy.exe')
mycommand = '"%s" "%s" "%s" "%s"' % (executable, source, dest, options)
result, output = command_runner(mycommand, shell=True)
我发现了什么:感谢 QuantumChris。我发现从终端机复制 returns 并返回到我的脚本中,尽管我使用了 subprocess.run 应该暂停我的脚本直到它完成 运行。在进行第二个 robocopy 之前,我通过检查文件是否已复制到目标文件夹来阻止 运行 的第二个 robocopy。问题是,如果最后一个文件很大,那么 os.path.isfile() 检测到文件 WHILE 时它仍在被复制。因此它使用第二个 robocopy 但是第二个 robocopy 没有检测到最后一个文件,因此尝试复制文件但认识到它无法访问该文件,因为它已经在使用中(由第一个 robocopy)所以它等待重试前 30 秒。 30 秒后,它可以访问该文件并将其复制过来。我现在想做的是让我的最后一个文件成为一个空的虚拟文件,我不关心它被复制两次,因为它是空的。 Robocopy 似乎根据 ASCII 顺序复制文件。所以我将文件命名为 ~~~~~.txt :D
尝试:
while temp2.poll() is not None:
# ... do something else, sleep, etc
out, err = temp2.communicate()
所以这个问题是 this 的后续问题(阅读评论以及我采取的路径)。我只希望第一个调用 robocopy 在继续执行其余代码之前完成执行。因为我希望第二个 robocopy 跳过所有文件,因为它们已经被复制了。然而,正在发生的事情是脚本的其余部分将 运行 (即启动第二个 robocopy),而第一个 robocopy 正在复制文件。下面是代码:
call(["start", "cmd", "/K", "RoboCopy.exe", f"{self.srcEntry.get()}", f"{self.dstEntry.get()}", "*.*", "/E", "/Z", "/MT:8"], stdout=PIPE, shell=True)
temp2 = Popen(["RoboCopy.exe", f"{self.srcEntry.get()}", f"{self.dstEntry.get()}", "*.*", "/E", "/Z"], stdout=PIPE, stdin=PIPE, shell=True)
编辑 1:
复制大文件时问题很明显。我正在考虑加入一个睡眠功能,该功能取决于要复制的文件的总大小。但是,这没有考虑 upload/download 速度,因为文件将通过网络传输。
我使用以下函数启动我的命令,该命令等待操作完成,但有一个超时:
import os
import logging
logger = logging.getLogger()
def command_runner(command, valid_exit_codes=None, timeout=30, shell=False, decoder='utf-8'):
"""
command_runner 2019103101
Whenever we can, we need to avoid shell=True in order to preseve better security
Runs system command, returns exit code and stdout/stderr output, and logs output on error
valid_exit_codes is a list of codes that don't trigger an error
"""
try:
# universal_newlines=True makes netstat command fail under windows
# timeout does not work under Python 2.7 with subprocess32 < 3.5
# decoder may be unicode_escape for dos commands or utf-8 for powershell
if sys.version_info >= (3, 0):
output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell,
timeout=timeout, universal_newlines=False)
else:
output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell,
universal_newlines=False)
output = output.decode(decoder, errors='backslashreplace')
except subprocess.CalledProcessError as exc:
exit_code = exc.returncode
# noinspection PyBroadException
try:
output = exc.output
try:
output = output.decode(decoder, errors='backslashreplace')
except Exception as subexc:
logger.debug(subexc, exc_info=True)
logger.debug('Cannot properly decode error. Text is %s' % output)
except Exception:
output = "command_runner: Could not obtain output from command."
if exit_code in valid_exit_codes if valid_exit_codes is not None else [0]:
logger.debug('Command [%s] returned with exit code [%s]. Command output was:' % (command, exit_code))
if output:
logger.debug(output)
return exc.returncode, output
else:
logger.error('Command [%s] failed with exit code [%s]. Command output was:' %
(command, exc.returncode))
logger.error(output)
return exc.returncode, output
# OSError if not a valid executable
except OSError as exc:
logger.error('Command [%s] faild because of OS [%s].' % (command, exc))
return None, exc
except subprocess.TimeoutExpired:
logger.error('Timeout [%s seconds] expired for command [%s] execution.' % (timeout, command))
return None, 'Timeout of %s seconds expired.' % timeout
except Exception as exc:
logger.error('Command [%s] failed for unknown reasons [%s].' % (command, exc))
logger.debug('Error:', exc_info=True)
return None, exc
else:
logger.debug('Command [%s] returned with exit code [0]. Command output was:' % command)
if output:
logger.debug(output)
return 0, output
# YOUR CODE HERE
executable = os.path.join(os.environ['SYSTEMROOT'], 'system32', 'robocopy.exe')
mycommand = '"%s" "%s" "%s" "%s"' % (executable, source, dest, options)
result, output = command_runner(mycommand, shell=True)
我发现了什么:感谢 QuantumChris。我发现从终端机复制 returns 并返回到我的脚本中,尽管我使用了 subprocess.run 应该暂停我的脚本直到它完成 运行。在进行第二个 robocopy 之前,我通过检查文件是否已复制到目标文件夹来阻止 运行 的第二个 robocopy。问题是,如果最后一个文件很大,那么 os.path.isfile() 检测到文件 WHILE 时它仍在被复制。因此它使用第二个 robocopy 但是第二个 robocopy 没有检测到最后一个文件,因此尝试复制文件但认识到它无法访问该文件,因为它已经在使用中(由第一个 robocopy)所以它等待重试前 30 秒。 30 秒后,它可以访问该文件并将其复制过来。我现在想做的是让我的最后一个文件成为一个空的虚拟文件,我不关心它被复制两次,因为它是空的。 Robocopy 似乎根据 ASCII 顺序复制文件。所以我将文件命名为 ~~~~~.txt :D
尝试:
while temp2.poll() is not None:
# ... do something else, sleep, etc
out, err = temp2.communicate()