实现一下功能:
1,mp4 视频文件提取 wav,pcm;
2,wav 切割为每段30s 的音频;
3,wav 切割后的音频转换为 pcm,ffmpeg无法将 pcm 文件切割
# 用 /bin/bash,需要执行 bash test.sh
# 用 /bin/bash ,执行 sh test.sh,会报错,可修改为: sudo ln -s /bin/bash /bin/sh
$0 是脚本本身的名字,$1 是给脚本传的第一个参数,$2 是传的第二个
root_dir="./data_video" #注意:"=" 两边不能有空格!
traversal_test.sh : 遍历文件夹
#!/bin/sh
# create date: 2022.04.14
# 用 /bin/bash,需要执行 bash test.sh
# 用 /bin/bash ,执行 sh test.sh,会报错,可修改为: sudo ln -s /bin/bash /bin/sh
function getdir(){
for element in `ls $1` # $0 是脚本本身的名字,$1 是给脚本传的第一个参数,$2 是传的第二个参数
do
# echo $element #文件名(不带路径)
dir_or_file=$1"/"$element
# echo $dir_or_file #文件名(带路径)
if [ -d $dir_or_file ] # -d filename: 如果 filename为目录,则为真
then
getdir $dir_or_file #再次调用getdir()
else
echo $dir_or_file
fi
done
}
root_dir="./data_video" #注意:"=" 两边不能有空格!
getdir $root_dir
if [ $suffix = 'mp4' ] #字符串变量,注意:[]里面两边需要空格
ffmpeg_v2a.sh :将音频从视频中提取出来
#!/bin/bash
# create by cw, date: 2022.04.14
# https://www.jianshu.com/p/eba436d46904
#` `和$( ) :在 bash shell 中,$()与``都是用来做命令替换的
# $和{ } 的用处:用来作变量替换
# 实现音频提取,转换,切割
# traversal for single folder
vedio_to_audio(){
startTime=`date +%Y.%m.%d-%H:%M:%S`
startTime_s=`date +%s` #从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数(时间戳)
# echo ${PWD} #当前路径
# folder="./data_video/"
# for file_a in ${folder}*
# for file in `ls $folder`
for file in `ls $1` # $0 是脚本本身的名字,$1 是给脚本传的第一个参数,$2 是传的第二个参数
do
# echo $file #文件名(不带路径)
dir_or_file=$1'/'$file #加上路径
# echo $dir_or_file #文件名(带路径)
in_filename=$dir_or_file
file=${in_filename##*/} #文件名: D01_20220330013446.mp4
filename=${file%.*} #无后缀: D01_20220330013446
suffix=${file##*.} #后缀: mp4
# echo $file, $filename, $suffix
# out_filename="$1"/data_audio/"${filename}".wav"" # new filename
out_filename="$1"/data_audio/"${filename}".pcm"" # new filename
# out_filename="$1"/"${filename}".mp3"" # new filename
# echo $in_filename
# echo $out_filename
if [ $suffix = 'mp4' ] #字符串变量,注意:[]里面两边需要空格
# if [ $num -eq 8 ] #整数变量
then
# echo "This is a mp4 file" # print for test
# ffmpeg -i $in_filename -acodec pcm_s16le -f s16le -ac 1 -ar 8000 -f wav $out_filename # *.wav
ffmpeg -i $in_filename -acodec pcm_s16le -f s16le -ac 1 -ar 8000 $out_filename # *.pcm
# ffmpeg -i D01_20220330013446.mp4 -acodec pcm_s16le -f s16le -ac 1 -ar 8000 -f wav D01_20220330013446.wav
# ffmpeg -i D01_20220330013446.mp4 -acodec pcm_s16le -f s16le -ac 1 -ar 8000 D01_20220330013446.pcm
# ffmpeg -i D01_20220330013446.mp4 -q:a 0 -map a D01_20220330013446.mp3
fi
done
endTime=`date +%y.%m.%d-%H:%M:%S`
endTime_s=`date +%s`
sumTime=$(( endTime_s - startTime_s ))
echo "$startTime ---> $endTime" "Total: $sumTime seconds"
}
# traversal for multiple folder
function getdir(){
startTime1=`date +%Y.%m.%d-%H:%M:%S`
startTime_s1=`date +%s` #从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数(时间戳)
for element in `ls $1` # $0 是脚本本身的名字,$1 是给脚本传的第一个参数,$2 是传的第二个参数
do
# echo $element #文件名(不带路径)
dir_or_file=$1"/"$element #加上路径
# echo $dir_or_file #文件名(带路径)
if [ -d $dir_or_file ] # -d filename: 如果 filename 为目录,则为真
then
getdir $dir_or_file #文件为目录,再次调用getdir()
echo $dir_or_file # print for test
else
# echo $dir_or_file # print for test
##### file processing #####
file=${dir_or_file%/*} #获取路径
# echo $file # print for test
# 如果目录不存在,则新建并处理
if [ ! -d "$file"/data_audio"" ]; # !-d filename: 如果目录不存在
then
mkdir "$file"/data_audio"" #如果目录不存在,则新建并处理
vedio_to_audio $file # convert from vedio to audio
echo "$file"/data_audio"": file has been created !
else
echo "$file"/data_audio"": file already exist !
fi
fi
done
endTime1=`date +%y.%m.%d-%H:%M:%S`
endTime_s1=`date +%s`
sumTime1=$(( endTime_s1 - startTime_s1 ))
echo "$startTime1 ---> $endTime1" "Total: $sumTime1 seconds"
}
# traversal for multiple folder to cut
function getdir_cut(){
startTime1=`date +%Y.%m.%d-%H:%M:%S`
startTime_s1=`date +%s` #从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数(时间戳)
for element in `ls $1` # $0 是脚本本身的名字,$1 是给脚本传的第一个参数,$2 是传的第二个参数
do
# echo $element #文件名(不带路径)
dir_or_file=$1"/"$element #加上路径
# echo $dir_or_file #文件名(带路径)
# ls -lh $dir_or_file
# mediainfo $dir_or_file
if [ -d $dir_or_file ]; # -d filename: 如果 filename 为目录,则为真
then
getdir_cut $dir_or_file #文件为目录,再次调用 getdir_cut()
# echo $dir_or_file # print for test
else
# echo $dir_or_file # print for test
##### file processing #####
# file=${dir_or_file%/*} #获取路径
file_new=${dir_or_file%.*} #去掉后缀
file_suffix=${dir_or_file##*.} #得到后缀
# echo $file_new # print for test
# echo $file_suffix
# 如果目录不存在,则新建并处理
# if [ ! -d "$file"/data_audio"" ]; # !-d filename: 如果目录不存在
# if [ ! -d $file_new -a $file_suffix = 'pcm' ] ; # -a: and -o: or
if [ ! -d $file_new -a $file_suffix = 'wav' ] ; # -a: and -o: or
# if [ ! -d $file_new ] && [ $file_suffix = 'wav' ] ; # 如果目录不存在,并且是wav文件
then
mkdir $file_new #如果目录不存在,则新建并处理
audio_cut $file_new #audio cut start !
echo $file_new: file has been created !
fi
fi
done
endTime1=`date +%y.%m.%d-%H:%M:%S`
endTime_s1=`date +%s`
sumTime1=$(( endTime_s1 - startTime_s1 ))
echo "$startTime1 ---> $endTime1" "Total: $sumTime1 seconds"
}
audio_cut(){
audio_in=$1
audio_name=${audio_in##*/} # D01_20220330013446
# echo $audio_name # print for test
num=1
while [ $num -le 142 ] # -lt :小于 less than,-le :小于等于 less than and be equal to
do
# if [ -e $1'.pcm' ]; #如果文件存在
if [ -e $1'.wav' ]; #如果文件存在
then
let time_stamp=num*30
#音频截取 -t 时间,同步
# ffmpeg -i D01_20220330013446.wav -ss 00:00:00 -t 00:00:30 output.wav
# ffmpeg -i D01_20220330013446.wav -ss 0 -to 60 output.wav #截取到 60s 时间戳
# ffmpeg -i D01_20220330013446.wav -ss 0 -t 30 output.wav #截取长度为 30s
# ffmpeg -i $1'.pcm' -ss $time_stamp -t 30 $1/$audio_name'_'$num'.pcm' #截取长度为 30s
ffmpeg -i $1'.wav' -ss $time_stamp -t 30 $1/$audio_name'_'$num'.wav' #截取长度为 30s
# 删除文件过小的文件!
# 获取文件大小的四种方式
# du -sh D01_20220330013446.wav | awk '{print $1}'
# ls -lh D01_20220330013446.wav | awk '{print $5}'
# wc -c D01_20220330013446.wav | awk '{print $1}'
# stat -c "%s" D01_20220330013446.wav
# value=$(du -s $1/$audio_name'_'$num'.wav' | awk '{print $1}')
# value=$( ls -l $1/$audio_name'_'$num'.pcm' | awk '{print $5}')
value=$( ls -l $1/$audio_name'_'$num'.wav' | awk '{print $5}')
# value=$(du -s D01_20220330013446.wav | awk '{print $1}')
echo "value:" $value
if [ $value -le '200' ] ; #文件大小不超过 200 bit
then
# rm $1/$audio_name'_'$num'.pcm'
# echo "delete $1/$audio_name'_'$num'.pcm' success !"
rm $1/$audio_name'_'$num'.wav'
echo "delete $1/$audio_name'_'$num'.wav' success !"
break
echo "break while loop !"
fi
let num++ # num add
fi
done
}
# traversal for multiple folder to transform wav to pcm
function getdir_wav2pcm(){
startTime1=`date +%Y.%m.%d-%H:%M:%S`
startTime_s1=`date +%s` #从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数(时间戳)
for element in `ls $1` # $0 是脚本本身的名字,$1 是给脚本传的第一个参数,$2 是传的第二个参数
do
# echo $element #文件名(不带路径)
dir_or_file=$1"/"$element #加上路径
# echo $dir_or_file #文件名(带路径)
if [ -d $dir_or_file ]; # -d filename: 如果 filename 为目录,则为真
then
getdir_wav2pcm $dir_or_file #文件为目录,再次调用 getdir_wav2pcm()
# echo $dir_or_file # print for test
else
# echo $dir_or_file # print for test
##### file processing #####
file_route=${dir_or_file%/*} #获取路径
file_folder_name=${file_route##*/}
file_new_pcm=${file_route%/*}'/data_pcm_cut'
file_new=${dir_or_file%.*} #去掉后缀
file_name=${file_new##*/}
file_suffix=${dir_or_file##*.} #得到后缀
# echo 00$file_new #./data_video/data_cut/D01_20220330024453/D01_20220330024453_99
# echo 11$file_suffix
# echo 22$file_route #./data_video/data_cut/D01_20220330024453
# echo 33$file_new_pcm #./data_video/data_cut/data_pcm_cut
# echo 44$file_name #D01_20220330024453_99
# echo $file_folder_name #D01_20220330024453
# pause() #程序暂停
# 如果目录不存在,则新建并处理
if [ ! -d $file_new_pcm ] ;
then
mkdir $file_new_pcm
fi
if [ ! -d $file_new_pcm'/'$file_folder_name ] ;
then
mkdir $file_new_pcm'/'$file_folder_name
fi
# if [ ! -d "$file"/data_audio"" ]; # !-d filename: 如果目录不存在
if [ $file_suffix = 'wav' ] ; # -a: and -o: or
# if [ ! -d $file_new ] && [ $file_suffix = 'wav' ] ; # 如果目录不存在,并且是wav文件
then
file_path_pcm=$file_new_pcm'/'$file_folder_name'/'$file_name'.pcm'
ffmpeg -i $dir_or_file -acodec pcm_s16le -f s16le -ac 1 -ar 8000 $file_path_pcm
echo $file_new_pcm: file has been created !
fi
fi
done
endTime1=`date +%y.%m.%d-%H:%M:%S`
endTime_s1=`date +%s`
sumTime1=$(( endTime_s1 - startTime_s1 ))
echo "$startTime1 ---> $endTime1" "Total: $sumTime1 seconds"
}
############### function call #################
# traversal for single folder !
# audio_dir="./data_video"
# audio_dir="/data/datasets/SED_202204/data_mp4"
# vedio_to_audio $audio_dir
# traversal for multiple folder !
# root_dir="./data_video" #注意:"=" 两边不能有空格!
# root_dir="/data/datasets/SED_202204/data_mp4"
# getdir $root_dir
# traversal for multiple folder to cut
# audio_dir="./data_video"
# audio_dir="/data/datasets/SED_202204/data_pcm" # ffmpeg无法对pcm裁剪,需要wav转pcm!
# audio_dir="/data/datasets/SED_202204/data_wav"
# getdir_cut $audio_dir
# traversal for multiple folder to transform wav to pcm
# audio_dir="./data_video/data_cut"
audio_dir="/data/datasets/SED_202204/data_wav_cut"
getdir_wav2pcm $audio_dir
***************************** 获取文件大小*********************
# awk 主要用来处理文件,将文本按照指定的格式输出。其中包含变量,循环以及数组。
# awk [选项] '匹配规则和处理规则' [处理文本路径]
# awk -F: '{print $1}' /etc/passwd
# 标准输出 | awk [选项] '匹配规则和处理规则'
# cat /etc/passwd | awk -F: '{print $1}'
du
du -sh D01_20220330013446.wav | awk '{print $1}'
ls
ls -lh D01_20220330013446.wav | awk '{print $5}'
wc
wc -c D01_20220330013446.wav | awk '{print $1}'
stat
stat -c "%s" D01_20220330013446.wav
Shell中获取单个文件大小_rockly89的博客-CSDN博客_shell 获取文件大小
***************************** 分割线 ****************************
# file=${in_filename##*/} #分别使用/和.作为分隔符来进行处理
# filename=${file%.*}
# suffix=${file##*.}
# echo $file, $filename, $suffix
# explain for #, %, ##, %% -- so useful
# ${in_filename##*/} # 从左边开始删除str中最大匹配(*/ 的字符串
# ${in_filename%/*} #从右边开始删除str中最小匹配/* 的字符串
# ${in_filename##*.} #从左边开始删除file中最大匹配*. 的字符串
# ${in_filename%.*} #从右边开始删除file中最小匹配.* 的字符串
# ${in_filename%%.*} #从右边开始删除file中最大匹配 .* 的字符串
# ${in_filename#*.} #从左边开始删除file中小匹配*. 的字符串
# #:表示从左边算起第一个
# %:表示从右边算起第一个
# ##:表示从左边算起最后一个
# %%:表示从右边算起最后一个
Linux shell中提取文件名和路径_yuyuena的博客-CSDN博客_shell获取路径中的文件名
***************************** 分割线 ****************************
Shell 脚本中 '$' 符号的多种用法
通常情况下,在工作中用的最多的有如下几项:
$0:Shell 的命令本身
$1 到 $9:表示 Shell 的第几个参数
$? :显示最后命令的执行情况
$#:传递到脚本的参数个数
$$:脚本运行的当前进程 ID 号
$*:以一个单字符串显示所有向脚本传递的参数
$!:后台运行的最后一个进程的 ID 号
$-:显示 Shell 使用的当前选项
参考博客:
Shell 脚本中 '$' 符号的多种用法_Jack Tian的博客-CSDN博客_shell中$
***************************** 分割线 ****************************
``和$( )的区别:
在 bash shell 中,$()与``(反引号Esc键下面那个键) 都是用来做命令替换用的。
区别在于``须要额外的跳脱( \` )处理。举个例子:
cmd1 `cmd2 \`cmd3\` `表示先执行cmd3,执行完之后交给cmd2再执行,最后再执行cmd1。
$和{ } 的用处:
用来作变量替换。
一般情况下,$var 与 ${var} 并没有啥不一样,但是用 ${ } 会比较精确的界定变量名称的范围。
( )和{ }的区别:
()和{}都是对一串的命令进行执行,但有所区别:
相同点:
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开
不同点:
()只是对一串命令重新开一个子shell进行执行,{}对一串命令在当前shell执行
()最后一个命令可以不用分号,{}最后一个命令要用分号
()里的第一个命令和左边括号不必有空格,{}的第一个命令和左括号之间必须要有一个空格
()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令
******************************* 整数计算****************************
二、shell变量---变量的数学运算,let i++实例_ 清欢渡.的博客-CSDN博客_shell 变量++
expr命令_Linux expr命令:四则远算和字符串运算
整数运算:
方法一:expr
echo $(expr 2 + 4)
expr 2 \* 5
expr \( 10 + 6 \) \* 3 + 10
方法二:$(( ))
echo $((1+2*5))
方法三:$[ ]
echo $[4*5-2]
方法四:let
let sum=2**4
echo $sum
小数运算:
awk 'BEGIN{…}' 可以进行小数运算
awk 'BEGIN{print 1/3+0.1}'
$(())的使用:
用来作整数运算
在 bash 中,$(( )) 的整数运算符号大致有这些:
+ - * / :分别为 "加、减、乘、除"。
% :余数运算
& | ^ !:分别为 "AND、OR、XOR、NOT" 运算。
a=5; b=7; c=2
echo $(( a+b*c ))
(()) 用于整数之间常用的运算符,效率高
let :用于整数运算,类似于(())
let 命令的语法格式为:
let 表达式
let "表达式"
let '表达式'
例子:
i=2
let i+=2
echo $i
******************************* 算术比较 ****************************
[]和[[]]的异同点:
1.相同点:
二者都支持算术比较和字符串比较表达式(具体使用可能有点不同)
条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。
2.不同点:
"["是一条命令, 与test等价,大多数shell都支持。
"[[",是关键字,许多shell(如ash bsh)并不支持这种方式
"[":逻辑与:"-a";逻辑或:"-o";"[[":逻辑与:"&&";逻辑或:"||"
[ expr ] 等于 test expr,对 test 命令来说, 用 -eq 要进行数字比较,而你此时传入字符串,就报错了。
[[]]用 -eq 进行数字比较时,不会报错,因为它直接把非整数的字符串直接转换成了 0
[[ ... ]]进行算术扩展,而[ ... ]不做
$ [[ 99+1 -eq 100 ]]&&echo true||echo false
四、shell中``和$()、$(())、${}、[]和[[]]使用_这个名字想了很久的博客-CSDN博客
***************************** 分割线 ****************************
linux 下shell中 if 的“-e,-d,-f”的意思
文件表达式
-e filename 如果 filename存在(exist),则为真
-d filename 如果 filename为目录(directory),则为真
-f filename 如果 filename为常规文件(),则为真
-L filename 如果 filename为符号链接(link),则为真
-r filename 如果 filename可读,则为真
-w filename 如果 filename可写,则为真
-x filename 如果 filename可执行,则为真
-s filename 如果文件长度不为0,则为真
-h filename 如果文件是软链接,则为真
filename1 -nt filename2 如果 filename1比 filename2新,则为真。
filename1 -ot filename2 如果 filename1比 filename2旧,则为真。
整数变量表达式
-eq 等于
-ne 不等于
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
字符串变量表达式
If [ $a = $b ] 如果string1等于string2,则为真
字符串允许使用赋值号做等号
if [ $string1 != $string2 ] 如果string1不等于string2,则为真
if [ -n $string ] 如果string 非空(非0),返回0(true)
if [ -z $string ] 如果string 为空,则为真
if [ $sting ] 如果string 非空,返回0 (和-n类似)
逻辑非 ! 条件表达式的相反
if [ ! 表达式 ]
if [ ! -d $num ] 如果不存在目录$num
逻辑与 –a 条件表达式的并列
if [ 表达式1 –a 表达式2 ]
逻辑或 -o 条件表达式的或
if [ 表达式1 –o 表达式2 ]
参考资料: