前段时间搭建了H大个人网盘,配合适当的节点速度不错。其中有music文件夹放些无损歌曲,奈何苹果不支持.flac格式的音乐文件播放;所以想到用ffmepg转换歌曲格式。随着歌曲增多,如何智能地批量执行flac2wav成了需求。

批量flac2wav

这个实现起来还算容易,主要借助shell写一个bash脚本走一个循环即可。

1
2
3
4
for i in *.flac
do
ffmpeg -i i $i.wav
done

但是问题显而易见的,$i获取的文件名含拓展名,那么,从$i中提取出所需文字成为新的目标。

shell提取文字

从以下文章可推知:shell提取文字大致分两种:

  • # % * $ {}符号提取文字
  • shell关键字basename和dirname
  • #:表示从左边算起第一个
  • %:表示从右边算起第一个
  • ##:表示从左边算起最后一个
  • %%:表示从右边算起最后一个
  • ${var%%x*}
  • *:表示删除
  • 起止位置由 %%x 表示:删除右边最后一个x,包含x的内容
    • %x时,*在x右边,其中x为目标位置
    • #x时,*在x左边,写作 ##*x

没有使用,想着用嵌套#%*代替

于是,提取到文件名变得可行,就有

1
2
name=${name%.*}  #删掉右边第一个"."及".",删掉拓展名
name=${name##*/} #删掉左边最后一个"/"及"/",删掉存储路径

转换过的需要跳过

批量flac2wav的问题似乎解决了,但又不是那么完整。比如:总不能每次将已经转换的文件再次转换吧?文件少时还好说,文件多时就要耗时了!
这个问题解决起来也容易,给转换过的歌曲建立列表。如果新的歌曲不再列表内,就转换;反之,则不转换。那么,就变成提取列表+转换前判断了。
已知的,我需要将wav格式的歌曲放在单独文件夹wav下,为了苹果设备的使用。就有:

已转换歌曲的目录

1
2
3
4
5
6
7
8
array_songs=() #建立空数组
for name in ../wav/*.wav
do
name=${name%.*} #删掉拓展名
array_songs=("${array_songs[@]}",${name##*/}) #删掉路径
done

echo ${array_songs[@]} #打印数组所有元素

判断是否转换

获取当前目录所有的.flac歌曲,并将每个名字与列表比对,就有:

1
2
3
4
5
6
7
8
9
10
11
12
for name in *.flac
do
name=${name%.*}
if [[ "${array_songs[@]}" =~ "${name}" ]]; then #已转换时

echo "${name}.flac 已转换成wav"
elif [[ ! "${array_songs[@]}" =~ "${name}" ]]; then #未转换时

echo "${name}.flac 正在转换成wav"
ffmpeg -i "${name}.flac" "../mac/${name%.*}.wav"
fi
done

让程序复用及人性化

如果没有提示语句,就会让程序生硬。如果没有程序复用,就显得冗余;所以使用了函数体。就有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/bin/bash

existSongsLine(){ #声明函数
echo "==================================================="
}

addSongsLine(){
echo "+++++++++++++++++++++++++++++++++++++++++++++++++++"
}

### 获取已转换的歌曲目录
existSongs(){
array_songs=()
for name in ../mac/*.wav
do
name=${name%.*}
array_songs=("${array_songs[@]}",${name##*/})
done
existSongsLine
echo ${array_songs[@]}
}

array_songs=($(existSongs)) #建立已转换歌曲的数组变量


#判断是否有新的歌曲需要转换成wav
for name in *.flac;do

name=${name%.*}
if [[ "${array_songs[@]}" =~ "${name}" ]]; then
existSongsLine
echo "${name}.flac 已转换成wav"
elif [[ ! "${array_songs[@]}" =~ "${name}" ]]; then
addSongsLine
echo "${name}.flac 正在转换成wav"
add=1
ffmpeg -i "${name}.flac" "../mac/${name%.*}.wav"
existSongsLine
echo "${name}.flac 已转换成wav"
fi
done

#提示歌曲是否增加,其实还可以加入打印歌曲数量的功能
if [[ ${add} -eq 0 ]]; then
echo -e "\n"
addSongsLine
echo "没有要转换的flac歌曲"
addSongsLine
fi

#打印已转换的歌曲
echo -e "\n已转换成wav的全部歌曲: "
existSongs

评论