Bash 如何将文件名提取为两个部分,一个放在目录中,另一个放在目录中?

Bash 如何将文件名提取为两个部分,一个放在目录中,另一个放在目录中?,bash,git-bash,Bash,Git Bash,我正在尝试按艺术家和姓名对所有mp3文件进行排序。目前,它们位于一个巨大的文件名中。 例如艺术家-歌曲名称.mp3 我想把这个转换成 艺人/歌曲名称.mp3 这是我到目前为止试过的。在本例中,我使用了一个名为“hi \-\hey”的测试文件: #/bin/bash #按当前工作目录中的所有.mp3扩展名筛选 对于*.mp3中的f;做 #提取艺术家和歌曲名称并删除空格 艺术家=${f%-*} 歌曲=${f#*-} #使用提取的艺术家名称创建目录,并将文件移动并重命名到该目录中 mkdir-p$艺术

我正在尝试按艺术家和姓名对所有mp3文件进行排序。目前,它们位于一个巨大的文件名中。 例如艺术家-歌曲名称.mp3 我想把这个转换成 艺人/歌曲名称.mp3

这是我到目前为止试过的。在本例中,我使用了一个名为“hi \-\hey”的测试文件:

#/bin/bash
#按当前工作目录中的所有.mp3扩展名筛选
对于*.mp3中的f;做
#提取艺术家和歌曲名称并删除空格
艺术家=${f%-*}
歌曲=${f#*-}
#使用提取的艺术家名称创建目录,并将文件移动并重命名到该目录中
mkdir-p$艺术家
mv$f$艺术家/$歌曲;
完成
出于某种原因,它正在创建一个目录,其中包含歌曲名而不是艺术家,此外还有大量错误:

mv: cannot move 'hey.mp3' to a subdirectory of itself, 'hey.mp3/hey.mp3'
mv: cannot stat 'hi': No such file or directory
mv: cannot stat '-': No such file or directory
mv: 'hey.mp3/hi' and 'hey.mp3/hi' are the same file
mv: cannot stat '-': No such file or directory

假设有很多文件,使用管道而不是for循环可能会更快。这样做的另一个好处是避免了复杂的、特定于bash的语法,并使用了核心unix/linux命令行程序

find *-*.mp3 |
  sed 's,\([^-]\+\)\s*-\s*\(.*\),mkdir -p "\1"; mv "&" "\1"/"\2",' |
  bash
说明:

find
用于查找当前目录中与-.mp3匹配的所有文件

sed
命令将每行更改为命令字符串,例如:

aaa - bbb.mp3
->
mkdir -p "aaa"; mv "aaa - bbb.mp3" "aaa"/"bbb.mp3"
bash
命令运行这些命令字符串中的每一个。

您可以试试这个

#!/usr/local/bin/bash
for f in *.mp3
do
artist=`echo $f | awk '{print $1}' FS=-`
song=`echo $f | awk '{print $2}' FS=-`
mkdir -p $artist
mv $artist-$song $song
mv $song ./$artist
done
这里我使用两个变量艺术家和歌曲。由于测试文件名为“hi \-\hey”,因此我将awk分隔符更改为“-”,以根据它存储变量

我们不需要使用awk..通过使用bash参数扩展。。。。它正在工作

#!/usr/local/bin/bash
for f in *.mp3
do
artist=`echo ${f%-*}`
song=`echo ${f#*-}`
mkdir -p $artist
mv $artist-$song $song
mv $song ./$artist
done

到目前为止,最简单的方法是使用
rename
a.k.a.Perl
rename

基本上,您希望用正斜杠目录分隔符替换序列SPACE-DASH-SPACE,因此命令为:

rename --dry-run -p 's| - |/|' *mp3
样本输出

'Artist - Song name.mp3' would be renamed to 'Artist/Song name.mp3'
'Artist B - Song name 2.mp3' would be renamed to 'Artist B/Song name 2.mp3'
如果这看起来是正确的,只需删除
--dry run
,然后再次实际运行即可。使用
重命名
的好处是:

  • 它可以在你真正跑步之前做一次测试
  • 它将使用
    -p
    选项创建所有必要的目录
  • 它不会在没有警告的情况下关闭(覆盖)文件
  • 您可以使用Perl的全部功能,并可以根据需要使重命名变得复杂

请注意,您可以使用自制macOS上安装:

brew install rename

以防您没有
rename
实用程序。对原始脚本的修复

for f in *.mp3; do
  # extract artist and song name and remove spaces
  artist=${f%% -*}
  song=${f##*- }
  #make directory with the extracted artist name and move + rename the file into the directory
  echo mkdir -p -- "$artist" && echo mv -- "$f" "$artist/$song"
done
  • 如果您对输出感到满意,请删除
    echo

引用您的变量。如果您尝试:echo mv$f$artist/$song,您可能会得到提示如果您的艺术家名称目录已经创建,则非常方便且更短:
prename的/*-*/\/'*.mp3
。这将重命名所有<代码>“艺术家姓名.mp3”<代码> >艺术家/No.mp3“<代码> >。尝试使用这样的引用:艺术家=“${f%-*}”//MKDIr -p“$艺术家”/等。考虑使用<代码>重命名< /代码> -它可以创建目录,干运行,计算和分割你想要的东西,你不需要
awk
进行简单的
cut
类操作。simple将在纯bash中实现这一点(就像OP所做的那样)。优点是-在不需要的时候不会产生一个过程。是的…阿尼希桑。。。谢谢你。。实际上,我正在开发tcsh shell,所以忘了使用这个..在这里我转换成bash,然后发布了这个。。