使用命令修改文本文件

使用命令修改文本文件

如何修改文本文件以在 1 个命令中执行以下操作?

Errors.txt我有一个名为以下三行的文本文件:

Error in File /Test1/A.png
Error in File /Test2/B.jpg
Error in File /Test3/C.jpg

我想要一个执行以下操作的命令:

  1. 找到每个“文件中的错误”并将其替换为"/mnt/HD
  2. "在每行末尾添加。
  3. 复制每一行,添加一个空格并粘贴该行
  4. 将每行的最后 4 个字符替换为webp"
  5. 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\nprint
  • /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"

相关内容