bash逐行更改文件中的绝对路径以创建脚本

bash逐行更改文件中的绝对路径以创建脚本,bash,sed,directory,move,absolute-path,Bash,Sed,Directory,Move,Absolute Path,我正在尝试基于输入文件(list.txt)创建一个bash脚本。输入文件包含具有绝对路径的文件列表。输出应该是一个bash脚本(move.sh),它将文件移动到另一个位置,保留文件夹结构,但在之前稍微更改目标文件夹名称 Input list.txt文件示例如下所示: /In/Folder_1/SomeFoldername1/somefilename_x.mp3 /In/Folder_2/SomeFoldername2/somefilename_y.mp3 /In/Folder_3/SomeFol

我正在尝试基于输入文件(list.txt)创建一个bash脚本。输入文件包含具有绝对路径的文件列表。输出应该是一个bash脚本(move.sh),它将文件移动到另一个位置,保留文件夹结构,但在之前稍微更改目标文件夹名称

Input list.txt文件示例如下所示:

/In/Folder_1/SomeFoldername1/somefilename_x.mp3
/In/Folder_2/SomeFoldername2/somefilename_y.mp3
/In/Folder_3/SomeFoldername3/somefilename_z.mp3
/gain/Folder_1/somefilename_x.mp3
/gain/Folder_2/somefilename_y.mp3
/gain/Folder_3/somefilename_z.mp3
创建后,输出文件(move.sh)应如下所示:

mv "/In/Folder_1/SomeFoldername1/somefilename_x.mp3"  /gain/Folder_1/
mv "/In/Folder_2/SomeFoldername2/somefilename_y.mp3"  /gain/Folder_2/
mv "/In/Folder_3/SomeFoldername3/somefilename_z.mp3"  /gain/Folder_3/
应该或多或少地保留文件夹结构

执行创建的bash脚本(move.sh)后,结果如下所示:

/In/Folder_1/SomeFoldername1/somefilename_x.mp3
/In/Folder_2/SomeFoldername2/somefilename_y.mp3
/In/Folder_3/SomeFoldername3/somefilename_z.mp3
/gain/Folder_1/somefilename_x.mp3
/gain/Folder_2/somefilename_y.mp3
/gain/Folder_3/somefilename_z.mp3
我到目前为止所做的一切

1.创建具有绝对路径的文件列表 2.创建move.sh脚本 rsync不是一个选项,因为我需要完全控制要移动的文件

我能做些什么更好地解决这个问题


EDIT:@Socowi为我指明了正确的方向,帮了我很多忙。在我深入研究正则表达式之后,我可以解决我的问题。非常感谢

它不是bash内置的,但是
mmv
命令非常适合这种需要在路径中使用通配符的
mv
。类似于以下的方法应该可以工作:

mmv "in/*/*/*" "#1/#3"
请注意,这不会为您创建目录-但在上面的示例中,这些目录似乎已经存在

该脚本只使用${fields[1]}的值,即文件夹_1,并将其放在末尾的所有行中。而不是文件夹2和文件夹3

迭代所有行,并为每行更新
字段。完成循环后,
字段
保留其值(从最后一行开始)。您必须将
sed
命令移动到循环中,并确保只有当前行被
sed
替换。然而,有一个更好的方法——见下文

我还能做得更好吗

例如,有很多事情你可以改进

  • 使用
    mapfile-d/fields
    而不是
    printf
    +
    cut
    +
    ($())
    创建数组
    字段
    。这样,路径中的空间也不会有问题
  • 仅使用
    sed
    一次,而不是创建数组
    字段
    并使用多个
    sed
    命令。您可以使用以下小脚本替换步骤2:
但是,最好的优化方法是放弃这三步方法,只使用一个脚本来查找和移动文件:

find /In/ -iname "*.mp3" -type f -exec rename -n 's|^/.*?/(.*?)/.*/(.*)$|/gain/$1/$2|' {} +
-n
选项将打印要重命名的内容,而不实际重命名任何内容。如果对结果满意,请删除
-n
。以下是输出:

rename(/In/Folder_1/SomeFoldername1/somefilename_x.mp3, /gain/Folder_1/somefilename_x.mp3)
rename(/In/Folder_2/SomeFoldername2/somefilename_y.mp3, /gain/Folder_2/somefilename_y.mp3)
rename(/In/Folder_3/SomeFoldername3/somefilename_z.mp3, /gain/Folder_3/somefilename_z.mp3)

您编写了
done
。你是说
done
done
只是第1行定义的
done
的副本。我保持
完成
用于其他活动。啊,我明白了。另一个问题;您想只移动mp3文件还是移动完整目录?如果您只想移动mp3文件:目标目录是否已经存在或是否应该创建?仅移动mp3。目标目录
/gain/Folder\u x/
已存在。但目录
/gain/Folder\u 1/SomeFoldername1
不存在。好的。我试图应用
sed-iE的^/[^/]*/([^/]*).$|mv“&”/gain/\1“|”/home/maars/mp3/move.sh
但是得到了一个错误:
sed:-e表达式1,char 40:s命令的RHS上的无效引用\1
sed
似乎不允许速记形式
-iE
。用
-i-E
再试一次。请参阅编辑。它使用了
-i-E
我需要使用
find/In/-iname“*.mp3”-type f-exec rename-n's |^/*?/(.*)/(.*)/(.*)$|/gain/$1/$2 |{}+
来理解它。因为它还没有给我任何输出。也许你有一个不同的
rename
比我想象的。在Ubuntu上,重命名是指向
/usr/bin/file rename
的符号链接。该程序由Larry Wall编写(请参见
man rename | grep-A1 AUTHOR
)和
rename--version
使用File::rename version 0.20打印
/usr/bin/rename。在其他系统上,相同的命令可能有不同的名称,例如
prename
。有关更多信息,请参阅和。我需要先安装
重命名
find /In/ -iname "*.mp3" -type f -exec rename -n 's|^/.*?/(.*?)/.*/(.*)$|/gain/$1/$2|' {} +
rename(/In/Folder_1/SomeFoldername1/somefilename_x.mp3, /gain/Folder_1/somefilename_x.mp3)
rename(/In/Folder_2/SomeFoldername2/somefilename_y.mp3, /gain/Folder_2/somefilename_y.mp3)
rename(/In/Folder_3/SomeFoldername3/somefilename_z.mp3, /gain/Folder_3/somefilename_z.mp3)