3

我正在尝试编写一个 shell 脚本,它递归地遍历一个目录,然后在每个文件中将所有 大写字母转换为小写字母。需要明确的是,我不是要更改文件名,而是要更改文件中的文本。

注意事项:

  1. 这是一个旧的 Fortran 项目,我正在努力使其更易于访问
  2. 我不想创建一个新文件,而是用更改覆盖旧文件
  3. 此目录中有几个不同的文件扩展名,包括 .par .f .txt 等

解决此问题的最佳方法是什么?

4

5 回答 5

6

要将文件从小写转换为大写,您可以使用ex(标准编辑器的好朋友ed):

ex -s file <<EOF
%s/[[:upper:]]\+/\L&/g
wq
EOF

或者,如果您喜欢一行内容:

ex -s file <<< $'%s/[[:upper:]]\+/\L&/g\nwq'

结合find,您可以执行以下操作:

find . -type f -exec bash -c "ex -s -- \"\$0\" <<< $'%s/[[:upper:]]\+/\L&/g\nwq'" {} \;

这种方法对于文件名中的空格和有趣符号是 100% 安全的。不创建、复制或移动辅助文件;文件只被编辑。

编辑。

使用glenn jackmann的建议,您还可以编写:

find . -type f -exec bash -c 'printf "%s\n" "%s/[[:upper:]]\+/\L&/g" "wq" | ex -- -s "$0"' {} \;

(优点是它避免了尴尬的逃跑;缺点是它更长)。

于 2012-11-27T22:07:00.203 回答
2

tr您可以使用命令并指定字符范围将所有大写字符 (A–Z) 转换为小写字符 (a–z) ,如下所示:

$ tr 'A-Z' 'a-z' <be.fore >af.ter

tr在为大写和小写转换指定这种范围时,还有一些特殊的语法:

$ tr '[:upper:]' '[:lower:]' <be.fore >af.ter

tr实用程序复制给定的输入以生成输出,并替换或删除选定的字符。tr 缩写为 translate 或 transliterate。它将两组字符作为参数,并将第一组中出现的字符替换为另一中的相应元素,即用于翻译字符。

tr "set1" "set2" < input.txt > output.txt

虽然tr不支持正则表达式,嗯,它确实支持一系列字符。

只需确保两个参数以相同数量的字符结束即可。如果第二个参数较短,则将重复其最后一个字符以匹配第一个参数的长度。如果第一个参数较短,则第二个参数将被截断以匹配第一个参数的长度。

于 2012-11-27T21:28:09.877 回答
2

sed -e 's/\(.*\)/\L\1/g' *

或者您可以通过管道将文件从 find

于 2012-11-27T22:47:17.900 回答
1

扩展@nullrevolution 的解决方案:

find /path_to_files -type f -exec sed --in-place -e 's/\(.*\)/\L\1/g' '{}' \;

这一行将查找以 /path_to_files 作为基本目录的所有子目录中的所有文件。

警告:这将更改 */path_to_file* 下每个目录中所有文件的大小写因此请确保在执行此脚本之前要执行此操作。您可以使用以下方法根据文件扩展名限制查找范围:

find /path_to_files -type f -name \*.txt -exec sed --in-place -e 's/\(.*\)/\L\1/g' '{}' \;

您可能还想在修改原始文件之前备份原始文件:

find /path_to_files -type f -name *.txt -exec sed --in-place=-orig -e 's/(.*)/\L\1/g' '{}' \;

这将保留原始文件名,同时制作未修改的副本,并在文件名后附加“_orig”(即file.txt将变为file.txt-orig)。

每件作品的解释:

find /path_to_file 这会将基本目录设置为提供的路径。

-type f这将仅在目录层次结构中搜索文件。

-exec COMMAND '{}' \; 这将为每个匹配的文件执行一次提供的命令。'{}'替换为当前文件名。表示命令的\;结束。

sed --in-place -e 's/\(.*\)/\L\1/g'--in-place将在不备份文件的情况下对文件进行 cnages。正则表达式使用反向引用\1来引用整行并\L转换为小写。

可选的

(对于更古老的解决方案。)

find /path_to_files -type f -exec dd if='{}' of='{}'-lc conv=lcase \;
于 2012-11-27T23:52:29.693 回答
0

在类 Unix 环境中识别文本文件可能有点棘手。你可以这样做:

set -e -o noclobber
while read f; do
   tr 'A-Z' 'a-z' <"$f" >"f.$$"
   mv "$f.$$" "$f"
done < <(find "$start_directory" -type f -exec file {} + | cut -d: -f1)

这将在带有嵌入冒号或换行符的文件名上失败,但应该适用于其他文件名,包括带有空格的文件名。

于 2012-11-27T21:45:28.493 回答