首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Bash to Python:平面目录树

Bash to Python:平面目录树
EN

Stack Overflow用户
提问于 2012-10-08 11:51:25
回答 1查看 2.5K关注 0票数 4

在类似Unix的系统上,我使用了这个脚本,我希望在移植到Python以在Windows主机上执行时提供一些帮助:

代码语言:javascript
复制
#!/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

您将如何移植这个以赢得Python?我是Python和Bash脚本的初学者。

如果您发现我的实现在任何方面都缺乏,请随时升级我的实现,请给出一个理由。这不是“代码审查”,而是对我在巴什的努力“竖起大拇指”,会让我感觉到我是在进步,还是应该彻底改变我的学习方式……

我们开始了,我在Python中的尝试:(如果需要的话,很难批评它,这是我学习的唯一方法!)

代码语言:javascript
复制
#!/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__目录中的文件
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-10-08 12:03:55

Python中的大多数文件处理函数都在模块"os“中--在其中您可以找到os.rename (用于重命名或移动一个目录条目),os.listdir --它为您提供目录中文件名的列表,作为第一个arg,os.walk传递--递归遍历目录结构os.path.walk进行同样的操作,但是使用回调、os.path.exists、os.path.isdir、os.mkdir等可能很方便。

对于“快速而肮脏”的翻译,您也可以使用"os.system“。它允许您执行一个shell命令,就像在shell中键入它一样,以及os.popen --它允许访问所述进程的stdin和stdout。一个更谨慎的转换,艰难,将需要使用anothe模块:“子进程”,它可以让一个完整的控制一个shell命令执行的子进程(虽然如果你需要find,例如,它将无法在窗口上使用)

其他感兴趣的模块有sys (sys.argv是传递给脚本的参数)和shutil (包括复制、rmtree等)。

您的脚本做了一些错误检查,考虑到上面在"os“和basic Python中添加它们的功能名称,这是很简单的,但是Python中的一个简短的”只做它“脚本可能只是:

代码语言:javascript
复制
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))
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12781161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档