我必须在 Bash 中找到恰好包含 16 行的文件。
我的想法是:
find -type f | grep '/^...$/'
有谁知道如何利用find
+grep
或find
+ awk
?
然后,
- 将匹配的文件移到另一个目录。
- 删除所有不匹配的文件。
我会这样做:
wc -l **/* 2>/dev/null | awk '$1=="16"'
把事情简单化:
find . -type f |
while IFS= read -r file
do
size=$(wc -l < "$file")
if (( size == 16 ))
then
mv -- "$file" /wherever/you/like
else
rm -f -- "$file"
fi
done
如果您的文件名可以包含换行符,那么谷歌查找和读取选项来处理它。
您应该使用grep
而不是wc
因为wc
计算换行符\n
并且如果最后一行不以换行符结尾则不计算在内。
例如
grep -cH '' * 2>/dev/null | awk -F: '$2==16'
对于更正确的方法(没有错误消息,并且没有参数列表太长的错误),您应该将其与find
andxargs
命令结合使用,例如
find . -type f -print0 | xargs -0 grep -cH '' | awk -F: '$2==16'
如果您不想计算空行(因此只有包含至少一个字符的行),您可以将 替换''
为'.'
. 而不是 awk,您可以使用第二个 grep,例如:
find . -type f -print0 | xargs -0 grep -cH '.' | grep ':16$'
这将找到包含 16 个非空行的所有文件......等等......
sed -E '/^.{16}$/!d' file
这个片段将完成工作:
find . -type f -readable -exec bash -c \
'if(( $(grep -m 17 -c "" "$0")==16 )); then echo "file $0 has 16 lines"; else echo "file $0 doesn'"'"'t have 16 lines"; fi' {} \;
因此,如果您需要删除不是 16 行长的文件,并将那些长 16 行的文件移动到 folder /my/folder
,这将是:
find . -type f -readable -exec bash -c \
'if(( $(grep -m 17 -c "" "$0")==16 )); then mv -nv "$0" /my/folder; else rm -v "$0"; fi' {} \;
请注意引用,"$0"
以便对任何带有有趣符号(空格,...)的文件名都是安全的。
我正在使用该-v
选项rm
并且mv
很冗长(我想知道发生了什么)。-n
选项mv
是 no-clobber:不覆盖现有文件的安全性;如果您有旧系统,则此选项可能不可用。
这种方法的好处。对于任何包含有趣符号的文件名,它都是非常安全的。
坏事。它为找到的每个文件分叉一个bash
和一个grep
和一个mv
或rm
。这可能很慢。这可以使用更棘手的东西来解决(同时对于文件名中的有趣符号仍然保持安全)。如果你真的需要,我可以给你一个可能的答案。如果文件不能(重新)移动,它也会中断。
评论。我正在使用-readable
to 选项find
,因此它只考虑可读的文件。如果您有此选项,请使用它,您将拥有更强大的命令!
我会去
find . -type f | while read f ; do
[[ "${f##*/}" =~ ^.{16}$ ]] && mv "${f}" <any_directory> || rm -f "${f}"
done
或者
find . -type f | while read f ; do
[[ $(echo -n "${f##*/}" | wc -c) -eq 16 ]] && mv "${f}" <any_directory> || rm -f "${f}"
done
替换<any_directory>
为您实际要将文件移动到的目录。
顺便说一句, find 命令将进入子目录。如果您不想要这个,那么您应该更改 find 命令以满足您的需要。
纯bash版本:
#!/usr/bin/bash
for f in *; do # Look for files in the present dir
[ ! -f "$f" ] && continue # Skip not simple files
cnt=0
# Count the first 17 lines
while ((cnt<17)) && read x; do ((++cnt)); done<"$f"
if [ $cnt == 16 ] ; then echo "Move '$f'"
else echo "Delete '$f'"
fi
done