Fazendo o md5sum entender nomes de arquivos com espaços


0

Eu preciso usar md5sumno Python usando pipe para calcular a soma de verificação para um monte de arquivos .mp3 ... existe um comando que ignora espaços em branco nos nomes de arquivos na linha de comando do md5sumprograma?

Por exemplo:

import os
def index(directory):
    stack = [directory]
    files = []
    while stack:
        directory = stack.pop()
        for file in os.listdir(directory):
            fullname = os.path.join(directory, file)
            if fullname.endswith('mp3'):
                files.append(fullname)
            if os.path.isdir(fullname) and not os.path.islink(fullname):
                stack.append(fullname)
    return files

def check(directory):
    files = index(directory)
    hvalues = []
    for x in files:
        cmd = 'md5sum' + ' ' + x
        fp = os.popen(cmd)
        res = fp.readline()
        hvalues.append(res)
        stat = fp.close() # What to do with stat?
    return hvalues

O comando cmd = 'md5sum' + ' ' + xnão funcionará como deveria nos arquivos que incluem espaços em branco ou caracteres especiais, porque a ferramenta 'md5sum' não possui a capacidade de manipular corretamente arquivos (hash) com espaços em branco nos nomes de arquivos.


Você poderia esclarecer sua pergunta com um exemplo? Como você está passando os nomes dos arquivos?
M_dk

Eu adicionei um exemplo de código.
Reloader

Respostas:


1

Isso não é falta de habilidades, md5toolmas uma restrição geral à linha de comando. Os argumentos são separados por espaços. Portanto, se você passar um nome de arquivo contendo espaços, md5sumele interpretará cada token como um único arquivo. Você pode contornar isso colocando o nome do arquivo entre aspas. Dito isto, tente substituir a linha

cmd = 'md5sum' + ' ' + x

com

cmd = 'md5sum' + ' "' + x + '"'

e sua chamada de linha de comando será semelhante

md5sum "file name with spaces.mp3"

Assim, md5sumcalculará o hash sem reclamar.


3

Como o @binfalse aponta, o problema não está no md5sumprograma, mas na maneira como você o invocou. Seu código é realmente ruim em vários níveis:

  1. Você montou um comando shell sem escapar. Na pior das hipóteses, isso pode levar à execução de um comando completamente não intencional, se um dos nomes de arquivos for criado de maneira inteligente. Isso seria horrível, a menos que você esteja escrevendo um script descartável de uso único.

  2. A os.popen()função está obsoleta desde o Python 2.6. A substituição recomendada é subprocess.Popen(). Certifique-se de passar uma lista como o argsparâmetro, não uma sequência concatenada, para evitar o problema de escape de shell mencionado anteriormente.

    def check(directory):
        files = index(directory)
        hvalues = []
        for f in files:
            cmd = ['md5sum', f]
            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
            hvalues.append(proc.stdout.readline())
            proc.stdout.close()
            stat = os.waitpid(proc.pid, 0)
        return hvalues
    
  3. Melhor ainda, use o Python hashlibpara calcular os hashes.


Obrigado por seus conselhos! Atualmente, estou aprendendo Python, então esse é um script descartável de aprendizado de pipe, mas, de qualquer forma, seus conselhos são inestimáveis ​​para mim!
Reloader

Ao "escapar", você se refere à adição da cláusula try / except?
Reloader

@ Reloader No: “escape” significa usar aspas no fragmento do shell, para que o shell saiba quais espaços separam argumentos e quais espaços fazem parte de um argumento. Os espaços e outros caracteres especiais que fazem parte de um nome de arquivo precisam ser escapados, ou seja, citados de alguma maneira.
Gilles

Você pode me ajudar a substituir os.popen () por subprocess.Popen ()?
Reloader

Estou recebendo, proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) NameError: global name 'subprocess' is not definedembora eu tenha declarado from subprocess import Popen, PIPEna primeira linha ...
Reloader 23/10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.