我正在尝试编写一个shell脚本,该脚本递归地遍历一个目录,然后在每个文件中将所有大写字母转换为小写。需要明确的是,我不是想更改文件名,而是想更改文件中的文本。
注意事项:
- 这是一个旧的Fortran项目,我正在努力使它更易于访问
- 我不想创建一个新文件,而是用更改来重写旧文件
- 该目录中有几个不同的文件扩展名,包括.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)
这将在嵌入冒号或换行符的文件名上失败,但在其他文件名上应该有效,包括带有空格的文件名。