使用特定行删除多个目录中的文件
Removing file in mutliple directory with specific line
我有这样的文件夹树:
00 -- 0
-- 1
...
-- 9
...
99 -- 0
-- 1
...
-- 9
在每个文件夹中,我都有带有某种奇怪文本的 .ini 文件。
如何删除第二行开头为 #
的文件?
我尝试使用:
for i in {00..99}; do for b in {0..9}; do grep -LZ -- # *.ini | xargs
-r0 rm; done; done
但是没有用。我想知道如何使用 sed
和 awk
来做到这一点,但我不知道怎么做。
使用足够新的 Awk 和 GNU find
你可以做到
awk 'FNR==2 { if ([=10=] ~ /^#/) printf "%s[=10=]", FILENAME; nextfile }' [0-9][0-9]/[0-9]/*.ini |
xargs -r0 echo rm
nextfile
statement 是一个 POSIX 扩展,但可能不会出现在非常古老的 Awk 实现中。如果您的文件很小,也许只需取出 nextfile
并忍受我们从每个文件末尾读取的轻微低效率,即使我们真的只需要检查第二行。
xargs
的 -0
选项是 GNU 扩展。如果你的文件名保证不包含换行符,你可能可以逃脱
awk 'FNR==2 { if ([=11=] ~ /^#/) print FILENAME; nextfile }' [0-9][0-9]/[0-9]/*.ini |
xargs -r echo rm
最后,删除 echo
以实际删除它打印的文件。
更详细地说,Awk 一次一行地处理每个输入文件,并分别评估每个文件的脚本。内置变量 FNR
设置为文件中的当前行号,FILENAME
是当前文件的名称。变量 [=21=]
包含整行,我们检查它是否匹配正则表达式 ^#
(行的开头,紧跟文字 #
字符);如果是这样,我们打印 FILENAME
(否则,该文件没有输出)。 nextfile
命令关闭当前文件并直接跳到参数列表中下一个文件的第一输入行(或者如果没有文件名需要处理则停止处理)。
如果你有很多匹配的文件,你不能像那样使用通配符(你会得到 "argument list too long");如果是这样,也许可以简单地恢复到原来的循环。
您尝试的直接错误是您需要在 #
周围加上引号(否则,它会将该行的其余部分标记为注释);但当然,您的 grep
会在文件中的任何位置查找该字符,并且您没有指定要检查的文件的路径。修复了即时错误后,那就是
# Don't use, still broken
for i in stuff; do
for b in more stuff; do
grep -LZ '#' "$i/$b"/*.ini
done
done |
# or simply grep -LZ '#' [0-9][0-9]/[0-9]/*.ini
xargs -r0 echo rm
但同样,您无法轻松解决此问题,只查看每个文件的第二行。 (另请注意我如何 运行 最后 xargs
在最后 done
之外。)
我有这样的文件夹树:
00 -- 0
-- 1
...
-- 9
...
99 -- 0
-- 1
...
-- 9
在每个文件夹中,我都有带有某种奇怪文本的 .ini 文件。
如何删除第二行开头为 #
的文件?
我尝试使用:
for i in {00..99}; do for b in {0..9}; do grep -LZ -- # *.ini | xargs
-r0 rm; done; done
但是没有用。我想知道如何使用 sed
和 awk
来做到这一点,但我不知道怎么做。
使用足够新的 Awk 和 GNU find
你可以做到
awk 'FNR==2 { if ([=10=] ~ /^#/) printf "%s[=10=]", FILENAME; nextfile }' [0-9][0-9]/[0-9]/*.ini |
xargs -r0 echo rm
nextfile
statement 是一个 POSIX 扩展,但可能不会出现在非常古老的 Awk 实现中。如果您的文件很小,也许只需取出 nextfile
并忍受我们从每个文件末尾读取的轻微低效率,即使我们真的只需要检查第二行。
xargs
的 -0
选项是 GNU 扩展。如果你的文件名保证不包含换行符,你可能可以逃脱
awk 'FNR==2 { if ([=11=] ~ /^#/) print FILENAME; nextfile }' [0-9][0-9]/[0-9]/*.ini |
xargs -r echo rm
最后,删除 echo
以实际删除它打印的文件。
更详细地说,Awk 一次一行地处理每个输入文件,并分别评估每个文件的脚本。内置变量 FNR
设置为文件中的当前行号,FILENAME
是当前文件的名称。变量 [=21=]
包含整行,我们检查它是否匹配正则表达式 ^#
(行的开头,紧跟文字 #
字符);如果是这样,我们打印 FILENAME
(否则,该文件没有输出)。 nextfile
命令关闭当前文件并直接跳到参数列表中下一个文件的第一输入行(或者如果没有文件名需要处理则停止处理)。
如果你有很多匹配的文件,你不能像那样使用通配符(你会得到 "argument list too long");如果是这样,也许可以简单地恢复到原来的循环。
您尝试的直接错误是您需要在 #
周围加上引号(否则,它会将该行的其余部分标记为注释);但当然,您的 grep
会在文件中的任何位置查找该字符,并且您没有指定要检查的文件的路径。修复了即时错误后,那就是
# Don't use, still broken
for i in stuff; do
for b in more stuff; do
grep -LZ '#' "$i/$b"/*.ini
done
done |
# or simply grep -LZ '#' [0-9][0-9]/[0-9]/*.ini
xargs -r0 echo rm
但同样,您无法轻松解决此问题,只查看每个文件的第二行。 (另请注意我如何 运行 最后 xargs
在最后 done
之外。)