如何修改文本文件以在 1 个命令中执行以下操作?
Errors.txt
我有一个名为以下三行的文本文件:
Error in File /Test1/A.png
Error in File /Test2/B.jpg
Error in File /Test3/C.jpg
我想要一个执行以下操作的命令:
- 找到每个“文件中的错误”并将其替换为
"/mnt/HD
。 "
在每行末尾添加。- 复制每一行,添加一个空格并粘贴该行
- 将每行的最后 4 个字符替换为
webp"
。 mv
在每行的开头添加。
我想要的结果是这样的:
mv "/mnt/HD/Test1/A.png" "/mnt/HD/Test1/A.webp"
mv "/mnt/HD/Test2/B.jpg" "/mnt/HD/Test2/B.webp"
mv "/mnt/HD/Test3/C.jpg" "/mnt/HD/Test3/C.webp"
答案1
从表面上回答你的问题:
1- 查找每个 {文件中的错误} 并将其替换为 {“/mnt}
sed 's/Error in File /"\/mnt/' Errors.txt
尽管你似乎确实想要
sed 's/Error in File /"\/mnt\/HD/' Errors.txt
2-在每行末尾添加 {"}
sed 's/$/"/' Errors.txt
3- 复制每一行,添加一个空格并粘贴该行
sed 's/.*/& &/' Errors.txt
4- 将每行的最后 4 个字符替换为 {webp"}
sed 's/....$/webp"/' Errors.txt
5-在每行开头添加 {mv}
sed 's/^/mv /' Errors.txt
因此(天真地),你可以把所有这些放在一起
sed -e 's/Error in File /"\/mnt\/HD/' -e 's/$/"/' -e 's/.*/& &/' -e 's/....$/webp"/' -e 's/^/mv /' Errors.txt
一种不那么零碎的方法是使用捕获组,就像这样
sed -E 's;Error in File (.*)(.{4})$;mv "/mnt/HD\1\2" "/mnt/HD\1.webp";' Errors.txt
其中使用;
sed 分隔符允许您/
在模式和/或替换文本中包含未转义的字符。
然而,如果你的目标是创建一组mv
命令并将它们传递给 shell 来执行它们,我建议你使用
sed -n 's;^Error in File ;/mnt/HD;p' Errors.txt |
while IFS= read -r f; do echo mv -n -- "${f}" "${f%.*}.webp"; done
此处,sed
命令用替换前导字符串Error in file
,/mnt/HD
并将结果行打印到标准输出流。然后while
循环读取整个线(可能包括空格或其他 shell 特殊字符)并确保在传递给mv
命令时它们被正确引用。
shell 替换${f%.*}
从文件中删除最短的点后缀 - 比盲目地删除最后 4 个字符更灵活。
echo
当您准备好mv
真正执行命令时,删除。
答案2
你可以用一行 perl 代码完成整个操作:
$ perl -lne '/Error in File (.+)\.(...)$/;
print "mv \"/mnt/HD$1.$2\" \"/mnt/HD$1.webp\""' Errors.txt
mv "/mnt/HD/Test1/A.png" "/mnt/HD/Test1/A.webp"
mv "/mnt/HD/Test2/B.jpg" "/mnt/HD/Test2/B.webp"
mv "/mnt/HD/Test3/C.jpg" "/mnt/HD/Test3/C.webp"
解释
perl -lne
:意思是“在输入文件的每一行上-n
运行给出的 perl 脚本;在每个调用后添加一个(即,它在打印后添加一个换行符,以便下一次打印在单独的行上)。-e
-l
\n
print
/Error in File (.+)\.(...)$/;
: 查找后面Error in File
跟空格的字符串,然后查找最长的字符串,直到.
(\.
将匹配文字.
,而.
单独表示“任何字符”) 后面跟任意三个字符 (...
) 直到行尾 ($
)。括号让您“捕获”匹配项,然后将其引用为$1
第一组括号、$2
第二组括号等等。因此,在此之后,文件名为$1
,扩展名为$2
。print "mv \"/mnt/HD$1.$2\" \"/mnt/HD$1.webp\""
:打印出mv
你想要的命令。
当然,既然您已经在使用 perl,不妨直接让它重命名文件(警告:这实际上会重命名文件):
perl -lne '/Error in File (.+)\.(...)$/;
rename("/mnt/HD$1.$2", "/mnt/HD$1.webp")' Errors.txt
上面的命令变成了这样:
$ tree /mnt/HD/
/mnt/HD/
├── Test1
│ └── A.png
├── Test2
│ └── B.jpg
└── Test3
└── C.jpg
4 directories, 3 files
变成这样:
$ tree /mnt/HD/
/mnt/HD/
├── Test1
│ └── A.webp
├── Test2
│ └── B.webp
└── Test3
└── C.webp
4 directories, 3 files
还有一种方法。如果您的Errors.txt
文件总是正如您所显示的,因此它始终具有精确的字符串Error in File
(包括末尾的空格),并且此后的所有内容都是您想要更改扩展名的文件名,您只需执行以下操作:
$ sed 's/Error in File //' Errors.txt | rename -n 's/...$/webp/'
/Test1/A.png -> /Test1/A.webp
/Test2/B.jpg -> /Test2/B.webp
/Test3/C.jpg -> /Test3/C.webp
如果看起来正确,请运行相同的命令,并选择-n
实际重命名。或者,如果您真的只想打印出命令而不做其他事情,您可以执行以下操作:
$ sed 's/Error in File //' Errors.txt |
while IFS= read -r file; do
printf 'mv "%s" "%s"\n' "$file" "${file%???}"webp;
done
mv "/Test1/A.png" "/Test1/A.webp"
mv "/Test2/B.jpg" "/Test2/B.webp"
mv "/Test3/C.jpg" "/Test3/C.webp"