V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
nowheretoseek
V2EX  ›  问与答

shell 脚本批量 mv 命令,如何提升速度?

  •  
  •   nowheretoseek · 2021-10-22 12:15:31 +08:00 · 1255 次点击
    这是一个创建于 1164 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用 shell 对上万个文件批量重命名,每行一个 mv 命令,速度比较慢且 CPU 占用高,大约 70 秒跑 1000 行命令,应该跟每行开了一个进程有关,怎么避免这种情况?试了下将 1000 行 mv 写入一行并用分号分隔,没用。

    10 条回复    2021-10-22 17:05:35 +08:00
    dzdh
        1
    dzdh  
       2021-10-22 12:28:27 +08:00
    经常要这么干吗?

    经常:源头解决,生成文件的时候就定好文件名,不能定的就写两份,定时删除老的
    不经常:管他干啥,反正一次性的操作 sh xx.sh > /dev/null 2>&1 & 睡觉去
    nowheretoseek
        2
    nowheretoseek  
    OP
       2021-10-22 12:31:05 +08:00
    @dzdh 不经常,只是记得 shell 脚本中分行写与并行写有些什么不同来着,想试着解决下,却不行
    AoEiuV020
        3
    AoEiuV020  
       2021-10-22 12:32:24 +08:00
    如果确定瓶颈是创建进程,就随便换个脚本语言都可以单进程直接调用系统调用重命名的,
    nowheretoseek
        4
    nowheretoseek  
    OP
       2021-10-22 12:37:17 +08:00
    @AoEiuV020 是的,python 脚本或者写个 sublimetext 插件都可以解决此问题
    mmtromsb456
        5
    mmtromsb456  
       2021-10-22 13:06:04 +08:00 via iPhone
    应当试试用 rename 命令来正则重命名,应该 10k+文件重命名都是有规律的吧
    ETiV
        6
    ETiV  
       2021-10-22 13:15:58 +08:00 via iPhone
    xargs 有一个 -P 参数,可以指定并发数
    nowheretoseek
        7
    nowheretoseek  
    OP
       2021-10-22 14:13:05 +08:00
    @mmtromsb456 有规律,但不是容易用规则表达的那种,还是编辑器做好列表再命名省事
    huntagain2008
        8
    huntagain2008  
       2021-10-22 15:27:50 +08:00   ❤️ 1
    本人非程序员。
    <试了下将 1000 行 mv 写入一行并用分号分隔,没用。
    $ mv xxx xxx;mv xxx xxx;mv xxx xxx
    这个是一串命令列表,前面的命令先运行,后面紧跟。实际和分行是一样的
    $ mv xxx
    $ mv xxx
    如果将分号分隔那串命令两端加上圆括号,就成了进程列表,生成了子 shell 来执行对应的命令。
    $ (mv xxx;mv xxx;mv xxx)
    "在 shell 脚本中,经常使用子 shell 进行多进程处理。但是采用子 shell 的成本不菲,会明显拖慢处理速度。在交互式的 CLI shell 会话中,子 shell 同样存在问题。它并非真正的多进程处理,因为终端控制着子 shell 的 I/O 。

    在交互式的 shell CLI 中,还有很多更富有成效的子 shell 用法。进程列表、协程和管道(后续会讲到)都利用了子 shell 。它们都可以有效地在交互式 shell 中使用。在交互式 shell 中,一个高效的子 shell 用法就是使用后台模式。在讨论如何将后台模式与子 shell 搭配使用之前,你得先搞明白什么是后台模式。
    在 CLI 中运用子 shell 的创造性方法之一就是将进程列表置入后台模式。你既可以在子 shell 中进行繁重的处理工作,同时也不会让子 shell 的 I/O 受制于终端。
    "
    那么将进程列表置入后台模式效果怎么样呢?楼主要不然试试。
    $ (mv xxx; mv xxx; 搞一千次)&
    或者用协程
    nowheretoseek
        9
    nowheretoseek  
    OP
       2021-10-22 17:04:28 +08:00
    @huntagain2008 谢谢,我试着用这个办法重命名了 2600 个文件,用了 125 秒,之前的办法估计要用 170 秒,进步挺名显。感觉 shell 执行这个任务差不多就这样了,试了下用 python 脚本只需 1.3 秒
    nowheretoseek
        10
    nowheretoseek  
    OP
       2021-10-22 17:05:35 +08:00
    python 脚本备用
    ```
    # coding: utf-8

    import shutil
    import time

    names = [x.split("\t") for x in open("names.txt", "r").read().strip().split("\n")]
    start = time.time()
    for name in names:
    old, new = name
    shutil.move(old, new)
    print(time.time() - start)
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2794 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:29 · PVG 20:29 · LAX 04:29 · JFK 07:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.