处理一大堆两行配置文件,我想要一种方法来排除任何具有不同行数的文件。
所以,像这样:
mv * destdir only if file contains exactly two lines
或者:
wc -l * | grep '^ *2' | xargs mv {} destdir
但这些都不是实际的工作代码。
在写这篇文章时我意识到我做有一种方法可以做到这一点,这很丑陋,我已将其作为答案包含在下面。
有没有一种简单/干净的方法来做到这一点?
答案1
你的笨拙的解决方案对于初学者来说还不错......你只是错过了这样一个事实:不仅可以awk
给你行数,你还可以指示它出口使用正确的状态代码,以便您可以使用以下命令链接它cp
:
for file in * ; do awk 'NR==3{exit}END{exit NR!=2}' "$file" && cp "$file" /tmp; done
NR
是记录数,并如建议的那样@don_crissti的答案,NR==3
一旦遇到第三行,我们就可以使用检查来停止进一步的处理。
NR!=2
看起来很有趣,因为awk
的true/false
值为1/0
,但在 shell 中,我们需要0
表示成功状态才能&&
正常工作。反之亦然(取决于你看到 时的反应有多强烈!=
):
for file in * ; do awk 'NR==3{exit}END{exit NR==2}' "$file" || cp "$file" /tmp; done
答案2
您可以在线使用awk
, (规则仍然执行),如果没有,则可以在块中使用 , 。行数不是例如:exit
3
END
exit 1
END
2
zsh
print -rl -- *(.e_'awk "NR==3{exit}END{if(NR!=2){exit 1}}" $REPLY'_)
将列出当前目录中的两行文件;如果您想移动它们,请替换print -rl
为mv
并添加目的地。
与其他外壳:
for file in ./*; do [[ -f $file ]] && \
awk 'NR==3{exit};END{if(NR!=2){exit 1}}' "$file" && mv "$file" "$dest"
done
其他方式,例如使用z
shell
和格努 awk
:
awk 'ENDFILE{if(FNR==2){print FILENAME}}' ./*(.)
或者格努 sed
(v.4.2.2
或稍后):
sed -ns '2{$F}' ./*(.)
列出两行文件1和 例如:
for f (./*(.))
sed -n '2{$Q 1};3q' $f || mv $f $dest
来移动他们。
1:这些都会经历整个输入,所以如果您正在处理大文件,那么不太适合;在这种情况下,您可能需要sed -n '2{$F};3q'
针对每个文件或使用第一个 awk 解决方案
答案3
如果您的文件名相当正常,并且您可以在两者:
和换行符上进行分隔,那么:
grep -m3 '' ./* ./*/* |
cut -d: -f1 | uniq -c |
grep -v '^ *[13] '
^该命令将列出当前目录和所有仅包含两行的直接子目录中的所有非点文件。
您实际上不需要担心 的排序uniq
,因为 glob 已排序。我使用 GNU ax match 选项,因为在第三个输入行退出比继续到最后-m
要快得多,但没有它也能工作。grep
这个想法是打印grep
它们包含的每一行的文件名,然后计算每个文件名在其输出中出现的次数,然后过滤掉任何大于或小于 2 的内容。
我针对一些随机源代码目录运行了它,并且在所有这些目录中,我有两个文件仅包含两行:
2 ./dex/coll.sh
2 ./jimtcl/jim-config.h.in
将最后一行替换为以下内容会更简洁:
... |
sed -ne's/^ *2 *//p'
...尽管。
答案4
使用 的-t
目标目录mv
选项xargs
:
wc -l * | sed -n 's/^[[:space:]]*2[[:space:]]\+//p' | xargs mv -t "$DESTDIR"