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

bash change absolute path in file line by line for script creation

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

输入 list.txt 文件示例如下所示:

/In/Folder_1/SomeFoldername1/somefilename_x.mp3
/In/Folder_2/SomeFoldername2/somefilename_y.mp3
/In/Folder_3/SomeFoldername3/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) 后,结果应如下所示:

/gain/Folder_1/somefilename_x.mp3
/gain/Folder_2/somefilename_y.mp3
/gain/Folder_3/somefilename_z.mp3

到目前为止我做了什么。

1。使用绝对路径创建文件列表

find /In/ -iname "*.mp3" -type f > /home/maars/mp3/list.txt

2。创建 move.sh 脚本

cp -a /home/maars/mp3/list.txt /home/maars/mp3/move.sh 
# read the list and split the absolute path into fields
while IFS= read -r line;do
fields=($(printf "%s" "$line"|cut -d'/' --output-delimiter=' ' -f1-))
done < /home/maars/mp3/move.sh
# add the target path based on variables at the end of the line
sed -i -E "s|\.mp3|\.mp3"\"" /gain/"${fields[1]}"/|g" /home/maars/mp3/move.sh
sed -i "s|/In/|mv "\""/In/|g" /home/maars/mp3/move.sh

该脚本仅使用 ${fields[1]} 的值,即 Folder_1 并将其放在末尾的所有行中。而不是 Folder_2 和 Folder_3。 当前结果看起来像

mv "/In/Folder_1/SomeFoldername1/somefilename_x.mp3"  /gain/Folder_1/
mv "/In/Folder_2/SomeFoldername2/somefilename_y.mp3"  /gain/Folder_1/
mv "/In/Folder_3/SomeFoldername3/somefilename_z.mp3"  /gain/Folder_1/

rsync 不是一个选项,因为我需要完全控制要移动的文件。

我怎样才能更好地解决这个问题?

编辑:@Socowi 为我指明了正确的方向,帮了我很多。在深入了解 Regex 世界之后,我可以解决我的问题。非常感谢

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

mmv "in/*/*/*" "#1/#3"

请注意,这不会为您创建目录 - 但在您上面的示例中,这些目录似乎已经存在?

The script just use the value of ${fields[1]}, which is Folder_1 and put this in all lines at the end. Instead of Folder_2 and Folder_3.

您遍历所有行并为每一行更新 fields。完成循环后,fields 保留其值(从最后一行开始)。您必须将 sed 命令移动到您的循环中,并确保只有当前行被 sed 替换。但是,还有更好的方法 – 请参阅下文。

What could I do better

有很多地方可以改进,例如

  • 正在使用 mapfile -d/ fields 而不是 printf+cut+($()) 创建数组 fields。这样,路径中的空格也不会有问题。
  • 只使用一次 sed 而不是创建数组 fields 并使用多个 sed 命令。您可以用这个小脚本替换第 2 步:
cp -a /home/maars/mp3/list.txt /home/maars/mp3/move.sh 
sed -i -E 's|^/[^/]*/([^/]*).*$|mv "&" "/gain/"|' /home/maars/mp3/move.sh

但是,最好的优化方法是放弃三步法,只使用一个脚本来查找和移动文件:

find /In/ -iname "*.mp3" -type f -exec rename -n 's|^/.*?/(.*?)/.*/(.*)$|/gain//|' {} +

-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)