You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ADB mv命令重命名Android文件时提示“非目录”错误求助

ADB批量重命名文件报错mv: ... not directory的解决思路

问题背景

在Windows系统通过ADB命令重命名Android设备文件时,频繁触发以下错误:

mv: '/storage/emulated/0/Download/xrn/folder/new_name.xml' not directory

执行的ADB命令格式为:

adb shell mv /path/to/old /path/to/new

因需求限制无法在设备端用Python或应用完成批量重命名,编写了如下Python脚本遍历目录重命名,但仍会触发上述错误:

import subprocess

def list_files_and_dirs(path):
    # Run the adb command to list files and directories
    result = subprocess.run(['adb', 'shell', 'ls', '-l', path], 
                            capture_output=True, text=True)
    
    # Initialize the result dictionary
    ret = {'files': [], 'dirs': []}
    
    # Check if the command was successful
    if result.returncode == 0:
        # Split the output into lines
        lines = result.stdout.splitlines()
        
        for line in lines:
            # Skip empty lines
            if not line.rstrip():
                continue
            print(line)
            # Split the line into parts (you may need to alter this line according to your adb shell ls output format)
            try :
                name = line.split(':')[1][3:].replace('\\', '')
            except :
                name = ''
                
            if name != '' :
               # The first part indicates the type (d for directory, - for file)
               entry_type = line[0]
               # The last part is the name of the file or directory
            
               if entry_type == 'd':
                   ret['dirs'].append(name)
               elif entry_type == '-':
                   ret['files'].append(name)
    
    else:
        print(f"Error: {result.stderr.strip()}")
    
    return ret

def new_name(n) :
    return b.b64encode(n. encode('utf-8')). decode('cp1250'). replace('+', '-'). replace('/', '_'). replace('=', '') + '.bn'

def rename_file(old_name, new_name):
    # Construct the adb command to rename the file
    command = ['adb', 'shell', 'mv', old_name, new_name]
    
    # Run the command
    result = subprocess.run(command, capture_output=True, text=True)

    print(command)
    
    # Check if the command was successful
    if result.returncode == 0:
        print(f"Successfully renamed '{old_name}' to '{new_name}'")
    else:
        print(f"Error: {result.stderr.strip()}")

def walk (p, l = 0) :
    array = list_files_and_dirs(p)# + '/*')
    for i in array['dirs'] :
        walk(p + '/' + i, l + 1)
    for i in array['files'] :
        print(p, '/', array)
        name = new_name(i)
        if '.bn' not in i :
            #print(i, name)
            rename_file('%s/%s' % (p, i), '%s/%s' % (p, name))

root = '/storage/emulated/0/Download/xrn'
walk(root)

核心原因与解决思路

1. 文件名解析逻辑依赖不稳定的ls -l输出

当前list_files_and_dirs函数通过line.split(':')[1][3:]提取文件名,这种方式完全依赖ls -l的输出格式,一旦文件名包含冒号、空格或特殊字符,就会提取失败,生成错误路径导致mv报错。
**解决:**改用ls -1(数字1)获取纯文件名列表,再通过stat命令判断文件类型:

def list_files_and_dirs(path):
    result = subprocess.run(['adb', 'shell', 'ls', '-1', path], 
                            capture_output=True, text=True)
    ret = {'files': [], 'dirs': []}
    if result.returncode == 0:
        lines = result.stdout.splitlines()
        for line in lines:
            line = line.strip()
            if not line:
                continue
            # 用stat判断文件/目录类型
            stat_result = subprocess.run(
                ['adb', 'shell', 'stat', '-c', '%F', f'{path}/{line}'],
                capture_output=True, text=True
            )
            if stat_result.returncode == 0:
                type_str = stat_result.stdout.strip()
                if type_str == 'directory':
                    ret['dirs'].append(line)
                elif type_str == 'regular file':
                    ret['files'].append(line)
    else:
        print(f"Error: {result.stderr.strip()}")
    return ret

2. 新文件名与目录重名导致mv行为异常

当生成的新文件名恰好和当前目录下的子目录同名时,mv会尝试将文件移入该目录,而非重命名,从而触发报错。
**解决:**重命名前先检查目标路径是否存在,若存在则生成唯一文件名:

import os

def check_path_exists(path):
    # 用test命令判断路径是否存在
    result = subprocess.run(
        ['adb', 'shell', 'test', '-e', path],
        capture_output=True, text=True
    )
    return result.returncode == 0

def rename_file(old_name, new_name):
    # 检查目标路径是否存在,存在则添加数字后缀
    if check_path_exists(new_name):
        base, ext = os.path.splitext(new_name)
        counter = 1
        while check_path_exists(f"{base}_{counter}{ext}"):
            counter += 1
        new_name = f"{base}_{counter}{ext}"
    command = ['adb', 'shell', 'mv', old_name, new_name]
    result = subprocess.run(command, capture_output=True, text=True)
    print(command)
    if result.returncode == 0:
        print(f"Successfully renamed '{old_name}' to '{new_name}'")
    else:
        print(f"Error: {result.stderr.strip()}")

3. 脚本的其他潜在问题修复

  • new_name函数中b.b64encode缺少base64模块导入,需补充import base64,并将b.b64encode改为base64.b64encode。
  • 手动拼接路径易出现重复斜杠(如//),改用os.path.join规范路径拼接:
    # 遍历目录时的路径拼接
    walk(os.path.join(p, i), l + 1)
    # 重命名时的路径拼接
    rename_file(os.path.join(p, i), os.path.join(p, name))
    
  • 删除walk函数中无用的print(p, '/', array)代码,避免干扰输出。

内容的提问来源于stack exchange,提问作者mxl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:42:17