Bash脚本,递归地使文件中的所有文本小写



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

注意事项:

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

对此最好的方法是什么?

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

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

或者,如果你喜欢一行的东西:

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

结合find,您可以执行:

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

对于文件名中的空格和有趣符号,此方法是100%安全的。未创建、复制或移动任何辅助文件;文件仅被编辑。

编辑

使用glenn jackmann的建议,你也可以写:

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

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

您可以使用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或音译。它采用两组字符作为参数,并将第一组中出现的字符替换为另一个的相应元素,即用于翻译字符。

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

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

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

sed -e 's/(.*)/L1/g' *

或者你可以通过管道将文件从find 中导入

扩展@nullrevolution的解决方案:

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

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

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

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

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

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

这将保留原始文件名,同时制作一个未经修改的副本,并在文件名后附加"_orig"(即file.txt将变为files.txtorig)。

每件作品的解释:

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

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

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

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

可选

(对于更陈旧的解决方案。)

find /path_to_files -type f -exec dd if='{}' of='{}'-lc conv=lcase ;

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

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)

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