【问题标题】:How do I extract a file name into 2 parts, making one into directory and the other one inside of it?如何将文件名提取为 2 个部分,将一个放入目录,另一个放入其中?
【发布时间】:2020-02-10 19:43:46
【问题描述】:

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

这是我迄今为止尝试过的。在这种情况下,我使用了一个名为“hi\ -\ hey”的测试文件:

#!/bin/bash
# filters by all .mp3 extensions in the current working directory 
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
        mkdir -p $artist
        mv $f $artist/$song;
done

出于某种原因,除了大量错误之外,它还使用歌曲名称而不是艺术家创建了一个目录:

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

【问题讨论】:

  • 引用你的变量。
  • 如果尝试,您可能会得到提示: echo mv $f $artist/$song
  • 如果您的艺术家姓名目录已经创建,perl rename 非常方便且更短:prename 's/ *- */\//' *.mp3。这会将所有 "artist - name.mp3" 重命名为 "artist/name.mp3"
  • 尝试使用这样的引号:artist="${f% -*}" // mkdir -p "$artist" // etc.
  • 考虑使用rename - 它可以创建目录、进行试运行、计算和拆分任何你想要的东西stackoverflow.com/a/49412361/2836621

标签: bash git-bash


【解决方案1】:

以防万一您没有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

【讨论】:

    【解决方案2】:

    到目前为止,最简单的方法是使用 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 并再次运行它。使用rename 的好处是:

    • 它可以在您真正运行之前进行试运行测试
    • 它将使用-p 选项创建所有必要的目录
    • 它不会在没有警告的情况下破坏(覆盖)文件
    • 您可以使用 Perl 的全部功能,并且可以根据需要进行复杂的重命名。

    请注意,您可以使用 homebrewma​​cOS 上安装:

    brew install rename
    

    【讨论】:

      【解决方案3】:

      你可以试试这个。

      #!/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
      

      【讨论】:

      • 简单的cut之类的操作不需要awk。简单的bash parameter expansion 将在纯 bash 中做到这一点(就像 OP 所做的那样)。优点是 - 在不需要时不生成进程。
      • ya...anishsane...谢谢你..实际上我正在研究 tcsh shell 所以忘记使用这个..在这里我转换为 bash 然后发布了这个..
      【解决方案4】:

      假设有很多文件,使用管道而不是 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 命令运行这些命令字符串中的每一个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-26
        • 2021-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-09
        • 1970-01-01
        相关资源
        最近更新 更多