4

在类 Unix 系统上,我使用这个脚本,我想要一些关于移植到 Python 以在 Windows 主机上执行的帮助:


#!/bin/bash

SENTINEL_FILENAME='__sentinel__'
SENTINEL_MD5_CHECKSUM=''
SENTINEL_SHA_CHECKSUM=''

function is_directory_to_be_flattened() {

  local -r directory_to_consider="$1"
  local -r sentinel_filepath="${directory_to_consider}/${SENTINEL_FILENAME}"

  if [ ! -f "${sentinel_filepath}" ]; then
    return 1
  fi

  if [[
      "$(
         md5 "${sentinel_filepath}" \
           | awk '{ print $NF }' 2> /dev/null
       )" \
        == "${SENTINEL_MD5_CHECKSUM}"
    && \
      "$(
         shasum -a 512 "${sentinel_filepath}" \
           | awk '{ print $1 }' 2> /dev/null
       )" \
        == "${SENTINEL_SHA_CHECKSUM}"
  ]]; then
    return 0
  else
    return 1
  fi
}

function conditionally_flatten() {

  local -r directory_to_flatten="$1"
  local -r flatten_into_directory="$2"

  if is_directory_to_be_flattened "${directory_to_flatten}"; then

    if [ ! -d "${flatten_into_directory}" ]; then
      mkdir -v "${flatten_into_directory}"
    fi

    for file_to_move in $(find ${directory_to_flatten} -type f -maxdepth 1); do
      mv \
        -v \
        -n \
        "${file_to_move}" \
        "${flatten_into_directory}"
    done
  fi
}

function flatten_directory() {

  local -r directory_to_flatten="$1"
  local -r descend_depth="$2"

  local -r flattened_directory="${directory_to_flatten}/__flattened__"

  if [ ! -d "${directory_to_flatten}" ]; then
    printf "The argument '%s' does not seem to be a directory.\n" \
      "${directory_to_flatten}" \
      >&2
    return
  fi

  find "${directory_to_flatten}" \
    -type d \
    -maxdepth "${descend_depth}" \
  | \
    while read directory_path; do
      conditionally_flatten \
        "${directory_path}" \
        "${flattened_directory}"
    done
}

n_arguments="$#"

if [ "${n_arguments}" -eq 1 ]; then
  flatten_directory "$1" '1' # maybe use a constant, not a "magic #" here?
else
  echo usage: "$0" /path/to/directory/to/flatten
fi

unset is_directory_to_be_flattened
unset conditionally_flatten
unset flatten_directory

您将如何将其移植到 Win Python?我是 Python 和 Bash 脚本的初学者。

如果您发现它也缺少任何方式,请在移植时随意升级我的实现,请说明理由。这不是“代码审查”,而是对我在 Bash 中的努力的“赞许/反对”会让我感觉到我是在进步还是应该完全改变我的学习方式......


好了,我在 Python 中的尝试:(如果需要,请严厉批评,这是我学习的唯一方法!


#!/usr/bin/env python2.7

import sys
import os
import shutil

SENTINEL_FILENAME=''
SENTINEL_MD5_CHECKSUM=''
SENTINEL_SHA_CHECKSUM=''

DEFAULT_DEPTH = 1
FLATTED_DIRECTORY_NAME = '__flattened__'

def is_directory_to_be_flattened(directory_to_consider):
  sentinel_location = os.path.join(directory_to_consider, SENTINEL_FILENAME)
  if not os.path.isfile(sentinel_location):
    return False
  import hashlib
  with open(sentinel_location) as sentinel_file:
    file_contents = sentinel_file.read()
    return (hashlib.md5(file_contents).hexdigest() == SENTINEL_MD5_CHECKSUM
      and hashlib.sha512(file_contents).hexdigest() == SENTINEL_SHA_CHECKSUM)

def flatten(directory, depth, to_directory, do_files_here):
  if depth < 0:
    return
  contained_filenames = [f for f in os.listdir(directory)]
  if do_files_here:
    for filename in contained_filenames:
      if filename == SENTINEL_FILENAME:
        continue
      filepath = os.path.join(directory, filename)
      if not os.path.isfile(filepath):
        continue
      file_to = os.path.join(to_directory, filename)
      if not os.path.isdir(to_directory):
        os.makedirs(to_directory)
      if not os.path.isfile(file_to):
        print "Moving: '{}' -> '{}'".format(filepath, file_to)
        shutil.move(filepath, file_to)
      else:
    sys.stderr.write('Error: {} exists already.\n'.format(file_to))
  next_depth = depth - 1
  for subdirectory in (d for d in contained_filenames if os.path.isdir(d)):
    if is_directory_to_be_flattened(subdirectory):
      flatten(subdirectory, next_depth, to_directory, True)

def flatten_directory(to_flatten, depth):
  to_directory = os.path.join(to_flatten, FLATTED_DIRECTORY_NAME)
  if not os.path.isdir(to_flatten):
    sys.stderr.write(
      'The argument {} does not seem to be a directory.\n'.format(
      to_flatten))
    return
  flatten(to_flatten, depth, to_directory, False)

def main():
  if len(sys.argv) == 2:
    flatten_directory(sys.argv[1], DEFAULT_DEPTH)
  else:
    print 'usage: {} /path/to/directory/to/flatten'.format(sys.argv[0])

if __name__ == '__main__':
  main()

虽然从代码中很明显,但意图是:

  • 从给定目录开始
  • 下降到一定深度
  • 当且仅当以下情况考虑子目录并移动其中的所有文件:
    • 该目录包含一个具有给定文件名的“哨兵文件”
    • 哨兵文件实际上是哨兵文件,而不仅仅是重命名为同名的文件
  • 整理__flattened__搜索开始目录下的目录中的文件
4

1 回答 1

9

Python 中的大多数文件处理函数都在模块“os”中——你会在其中找到 os.rename(用于重命名或移动目录条目)、os.listdir——它为你提供目录中的文件名列表,作为第一个参数传递, os.walk - 递归遍历目录结构 os.path.walk, 做同样的事情, 但使用回调, os.path.exists, os.path.isdir, os.mkdir, 是其他可能的便利。

对于“快速而肮脏”的翻译,您还可以查看“os.system”。它允许您执行 shell 命令,就像它在 shell 中键入一样,而 os.popen - 允许访问所述进程的标准输入和标准输出。更仔细的翻译,艰难,需要使用另一个模块:“子进程”,它可以完全控制作为子进程执行的 shell 命令(尽管如果你需要find,例如,它在 Windows 上不可用)

其他感兴趣的模块是sys(sys.argv 是传递给脚本的参数)和shutil(与复制、rmtree 等类似的东西)

您的脚本会进行一些错误检查,这很简单,因为上面的“os”和基本 Python 中的函数名称可以添加它们 - 但是 Python 中的一个简短的“只是做”脚本可能只是:

import os, sys

dir_to_flatten = sys.argv[1]

for dirpath, dirnames, filenames in os.walk(dir_to_flatten):
    for filename in filenames:
        try:
            os.rename(os.path.join(dirpath, filename), os.path.join(dir_to_flatten, filename))
        except OSError:
            print ("Could not move %s " % os.path.join(dirpath, filename))
于 2012-10-08T12:03:55.303 回答