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)
我正在尝试根据输入文件 (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)