ここでUbuntu Linuxを実行します。
PWDですべてのmp3ファイルを検索し、mp3infoを使用して各持続時間を分単位で取得し、合計し、pwd内のすべてのmp3の合計持続時間を印刷するターミナルコマンドがあります。
for file in *.mp3; do
mp3info -p "%S\n" "$file"
done | paste -sd+ | sed 's+\(.*\)+(\1)/60+' | bc
出力例:
$ for file in *.mp3; do
mp3info -p "%S\n" "$file"
done | paste -sd+ | sed 's+\(.*\)+(\1)/60+' | bc
47
したがって、PWDには47分のmp3があります。
私はこれをすべてのサブディレクトリに再帰し、名前を印刷し、各フォルダ内のすべてのmp3の合計持続時間を一覧表示するbashスクリプトにしたいと思います。たとえば、次のようになります。
foldernameA
45
foldernameB
89
foldernameC
17
など。
私が試したこと( "durations.sh"):
#!/bin/bash
find . -type d -execdir sh -c 'for file in *.mp3;
do
mp3info -p "%S\n" "$file";
done
| paste -sd+ | sed 's+\(.*\)+(\1)/60+' | bc
しかし、これは悲惨に失敗します。
$ ./durations.sh
./durations.sh: line 6: syntax error near unexpected token `('
./durations.sh: line 6: `| paste -sd+ | sed 's+\(.*\)+(\1)/60+' | bc'
私は明らかに私が何をしているのかわかりません。
答え1
forループを直接使用できますshopt -s グロスター:
グローバルスター
設定されている場合、ファイル名拡張子のコンテキストで使用される "**"パターンは、すべてのファイルとゼロ個以上のディレクトリとサブディレクトリと一致します。パターンの後に「/」が続くと、ディレクトリとサブディレクトリのみが一致します。
shopt -s globstar
d=0;
for file in **/*.mp3; do
d=$((d + $(mp3info -p "%S" "$file")))
done
mins=$(echo "$d / 60" | bc)
secs=$(echo "$d % 60" | bc)
echo "Total $mins minutes and $secs seconds"
答え2
単一フォルダの長さを一覧表示するには、ダブルループが必要です。最初のループはディレクトリを一覧表示し、2番目のループは各ディレクトリのファイルを一覧表示します。
#!/bin/bash
OIFS="$IFS"
IFS=$'\n'
function secondToTime () { #Convert second to Day, Hours, Minutes, Seconds
seconds=$1
min=0
hour=0
day=0
if((seconds>59));then
((sec=seconds%60))
((seconds=seconds/60))
if((seconds>59));then
((min=seconds%60))
((seconds=seconds/60))
if((seconds>23));then
((hour=seconds%24))
((day=seconds/24))
else
((hour=seconds))
fi
else
((min=seconds))
fi
else
((sec=seconds))
fi
echo "$day"d "$hour"h "$min"m "$sec"s
}
case $1 in #loop though the first argument
'-h'|'--help') # Display the help and exit
echo "Usage: $0 [PATH]"
echo "Display the total play time of each folder"
exit 0
;;
!'') # Will use the argument as target path
target=$1
;;
*) # If no argument is specify it will use the current path
target='.'
;;
esac
for folders in `find $1 -type d ` # Find all sub folders in the specifyed path
do
for folder in $folders # Loop though each folders
do
echo Folder $folder:
folderTime=0;
for file in `ls $folder/*.mp3 2> /dev/null` #loop though each files in each folders
do
fileTime=`mp3info -p "%S\n" "$file"` #get the time lenght of $file
isNumber=`echo $fileTime | grep -E '^\-?[0-9]+.?[0-9]*$'` #grep only numbers, if it's not a number isNumber will be empty
if [ "$isNumber" != '' ] # Check if $isNumber is NOT empty (which mean that it's a number)
then
let "folderTime=$fileTime+$folderTime" #Calculate Total duration in seconds
fi
done
secondToTime $folderTime # Convert seconds to days hours minutes seconds and print it out
done
done
IFS=$OIFS