Bash - 计算一个文件夹中所有 mp3 文件的长度

Posted

技术标签:

【中文标题】Bash - 计算一个文件夹中所有 mp3 文件的长度【英文标题】:Bash - calculate length of all mp3 files in one folder 【发布时间】:2017-08-06 19:43:55 【问题描述】:

我有以下命令返回 mp3s 文件的文件名和长度:

mp3info -p "%f: %m:%02s\n" *.mp3

如何在 bash 脚本中使用它来返回给定目录中所有 mp3 文件的总长度(总和)?我想要以下符号:mm:ss

【问题讨论】:

请编辑您的 Q 以显示该命令的 3-5 行输出以及您希望最终输出(给定该示例输入)看起来的确切格式。如果您有任何代码,最好以 S.O. 的身份分享。不是真正的代码编写服务。我们很乐意帮助您解决问题。也许您想查看grymoire.com/Unix/awk.html 以了解专为此类问题设计的工具。 awk 作为 std 安装的一部分在所有 Unix/Linux 平台上可用。祝你好运。 可能相关:***.com/questions/8933053/… 【参考方案1】:

我会采用三步法:

    不打印filename.mp3: mm:ss\n,而是省略文件名并打印总秒数 根据结果构建算术表达式,为您提供总秒数 除以 60,四舍五入得到分钟,计算秒的余数。

第一步很简单

mp3info -o '%S' 

将完成这项工作。现在,我们想让事情给我们一个有效的数字表达式,形式为

时间1+时间2+....

所以,

mp3info -o '%S + '

看起来很聪明。

然后,因为 mp3info 打印的最后一件事将是 +,所以让我们添加一个零:

"$(mp3info -o '%S + ') 0"

并在算术表达式中使用该字符串:

total_seconds=$(( $(mp3info -o '%S + ' *.mp3) 0 ))

现在,获取完整的会议记录:

full_minutes=$(( total_seconds / 60 ))

剩下的秒数

seconds=$(( total_seconds % 60 ))

所以整个脚本看起来像

#!/bin/bash 
# This code is under GPLv2
# Author: Marcus Müller

total_seconds=$(( $(mp3info -o '%S + ' *.mp3) 0 ))

printf "%02d:%02d\n" $((total_seconds / 60)) $((total_seconds % 60))

【讨论】:

要以mm:ss 格式打印,请使用printf,如下所示:printf "%02d:%02d\n" $((total_seconds / 60)) $((total_seconds % 60)) @randomir 我认为这是零优势。它更长,更难阅读,效率更低。啊,你的意思是两位数符号,是的,好的,点了 .. 它打印前导零。 是的,我的错。我认为功劳应该归于你——你介意编辑我的答案吗? 最终版本中的小错字 -o 而不是 -p【参考方案2】:

mp3info 中的基本计算容易出错,因为元数据不是真实数据。使用sox(瑞士军队音频工具)可以直接从mp3文件中获取。

R=0
for a in *.mp3
do
  T="$(soxi -D $a 2>-)"
  echo $T
  [[ "$T" != "" ]] && R="$R + $T"
done
echo $R | bc

如果你想要几个小时

echo "($R) / 60" | bc

对于较长的 mp3 列表,最好在每个循环中求和持续时间

【讨论】:

这挂起并且显然更改了目录中的文件名(“01 - ...”已更改为“-”。也许“2>-”应该是“2>/dev/null”。 "$a" 需要引号来正确处理带有空格的文件名。更好的是,将其称为更具描述性的名称,例如“$TRACK”(我的变量命名宠儿......)。【参考方案3】:

当在仅包含音乐文件的目录中使用此 Bourne shell 单行程序时,将以非常高的精度输出它们的总长度(以秒为单位):

LENGTH=0; for file in *; do LENGTH="$LENGTH+$(ffprobe -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)"; done; echo "$LENGTH" | bc

修改为仅输出 .mp3 文件的长度(从而避免破坏我们音乐目录中无害的 .docx),它看起来像这样:

LENGTH=0; for file in *.mp3; do if [ -f "$file" ]; then LENGTH="$LENGTH+$(ffprobe -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)"; fi; done; echo "$LENGTH" | bc

例如,如果我们想输出只有几个不同文件扩展名的音频总长度,我们也可以通过添加第二个通配符来做到这一点,同时仍然避免可怕、可怕的 .docx:

LENGTH=0; for file in *.mp3 *.ogg; do if [ -f "$file" ]; then LENGTH="$LENGTH+$(ffprobe -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)"; fi; done; echo "$LENGTH" | bc

当然,必须安装 ffmpeg 才能使用其中任何一个。

【讨论】:

【参考方案4】:

这是@albfan 的一种变体,带有描述性变量名称和语法突出显示。它适用于整个目录(专辑)。

#!/bin/bash

TOTAL=0

for ALBUM in *
do
    if [ -d "$ALBUM" ] ; then
        ALBUM_TIME=0
        echo $ALBUM

        # Make `cd` quiet
        cd "$ALBUM" &>/dev/null
        for TRACK in *.mp3; do
            TRACK_TIME="$(soxi -D "$TRACK" 2>/dev/null)"
            # noisy
            # echo "Track duration: $TRACK_TIME"
            [[ "$TRACK_TIME" != "" ]] && ALBUM_TIME="$ALBUM_TIME + $TRACK_TIME"
        done
        # Convert summation to a single number for efficiency
        ALBUM_TIME=`echo $ALBUM_TIME | bc`
        # This has to be two stmts?
        echo -n "Album time (min): "; echo 'scale=2;' $ALBUM_TIME / 60 | bc
        echo # line break
        TOTAL="$TOTAL + $ALBUM_TIME"
        cd ..
    fi

    # Evaluate the expression
    TOTAL=`echo $TOTAL | bc`

done

echo -n "Total time (hrs): "; echo 'scale=2;' $TOTAL / 3600 | bc

【讨论】:

以上是关于Bash - 计算一个文件夹中所有 mp3 文件的长度的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 bash 脚本从 base64 转换的文件中播放声音?

jsp中如何计算上传的mp3文件的时长

Bash:无法通过 mediainfo 浏览目录中的所有文件

编写一个简单的 python 脚本,使用 lame 将特定文件夹中的所有 .wav 文件转换为 .mp3

如何在 Flutter 中从内部和外部存储中获取所有 mp3 文件?

使用ffmpeg将文件夹中的所有mp4音频文件转换为mp3 [重复]