在python脚本中实现管道化的xargs rm和tee命令

时间:2019-01-17 16:22:39

标签: python python-2.7 unix

我有一个python脚本,可以根据特定的通配符模式和特征打印出文件名。然后,我将一些命令传送到此打印输出列表,并用xargs rm删除列出的文件。该脚本在UNIX服务器上运行,通常,我将按以下方式运行脚本:

python deletefiles.py <directory> <wildcard1> | tee deletedfiles.txt | xargs rm

这一切正常运行,但是我试图找到一种方法,使teexargs rm命令已经在脚本中,以便用户不必将其键入到脚本中。命令。

我已经看过网上了,人们对import subprocess说,但是我不了解如何结合我的脚本使用它的完整语法。

截至目前,在unix系统上运行的代码很简单

if len(sys.argv) == 3:
    try:
        input_directory = sys.argv[1]
        input_delete = sys.argv[2].split(',') \\patterns to delete
    except ValueError:
        "Please enter a valid input"

我想做的是实现对另一个参数的检查,分析/删除,其中analyze仅允许脚本执行打印文件名的工作,并且如果参数为delete ,脚本将xargs rmtee这些文件。

我不确定如何解决这个问题,因为使用python脚本打印文件的主要目的是使xargs rmtee deletedfiles.txt在删除时有一些不足之处/保存到文本文件。我想知道是否有办法在python脚本中有条件地做到这一点

如果我需要提供有关脚本的更多信息,我很乐意

2 个答案:

答案 0 :(得分:0)

您可以将它们作为子进程运行。不过,还有更好的选择。见下文。

假设files包含您的文件名,

from subprocess import Popen, PIPE
p = subprocess.Popen("tee '{0}' | xargs rm".format(teefile),
    shell=True, stdin=PIPE)
p.communicate('\n'.join(files))

但是,这两种操作在Python本机中都是微不足道的。

with open(teefile, "w") as tee:
    for file in files:
        tee.write(file + '\n')
        os.unlink(file)

我想您会同意后者更简单,更优雅(尽管在Python 3中,subprocess也可以变得更简单;您确实想准备尽快转换为Python 3。)

答案 1 :(得分:-1)

本来我只是想发表评论,但我认为这更容易理解。

Python有一个名为argparse的模块来处理命令行参数。这些示例有些混乱,因此建议您凝视下面的get_args,直到有意义为止。

您可以尝试在python脚本本身中完成所有这些操作,而不必尝试将其通过管道传递到teexargs rm

这里有一个您可以借鉴的示例:

#!/usr/bin/env python2

# allows us to use python3 print function
from __future__ import print_function

import os
import fnmatch
import sys
import argparse


def get_args():
    parser = argparse.ArgumentParser()
    # note directory has `required=True`, that means the user must provide it
    parser.add_argument("--directory", help="Directory to analyze", required=True)
    # store_true stores a boolean depending on whether or not the flag was present
    parser.add_argument("--delete", help="Delete the files which should be removed", action="store_true", default=False)
    args = parser.parse_args() # parses, makes sure all conditions are met, exits if user didn't provide a filename
    return args


def analyze(directory):
    # do whatever wildcarding here to return a list of files
    # heres just an example, remove all *.txt files recursively
    files_to_delete = []
    for root, dirnames, filenames in os.walk(directory):
        # fnmatch is unix-like filename matching
        for filename in fnmatch.filter(filenames, "*.txt"):
            # abspath gives us the full path, root is the original directory
            files_to_delete.append(os.path.abspath(os.path.join(root, filename)))
    return files_to_delete


def delete(files):
    # write to deleted_files.txt in this function
    deleted_file = open("deleted_files.txt", 'w')
    for f in files:
        if os.path.exists(f): # filepath exists
            if os.path.isfile(f): # is a file (not a directory)
                os.remove(f) # remove it
                deleted_file.write("{}\n".format(f)) # write to the file
            else:
                print("Could not remove {}, is not a file".format(f), file=sys.stderr)
        else:
            print("Could not remove {}, does not exist".format(f), file=sys.stderr)
    deleted_file.close()


def main():
    args = get_args()
    files = analyze(args.directory)
    # if the user gave us the --delete flag
    if args.delete:
        delete(files)
    else:
        # just print it out to the user
        for f in files:
            print(f)

if __name__ == "__main__":
    main()

如果您只想保存应删除的文件,请将输出重定向到文件

python2.7 deletefiles.py --directory test_dir > files_to_delete.txt

如果要删除它们:

python2.7 deletefiles.py --directory test_dir --delete

然后您可以cat deleted_files.txt来获取已删除的文件。

这里有一些我使用的功能的文档:

fnmatch.filtersys.stderros.path.joinos.path.abspathos.path.isfileos.walkos.remove

如果要删除目录,请查看os.removedirs