仅列出(或移动)具有一定行数的文件?

仅列出(或移动)具有一定行数的文件?

处理一大堆两行配置文件,我想要一种方法来排除任何具有不同行数的文件。

所以,像这样:

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看起来很有趣,因为awktrue/false值为1/0,但在 shell 中,我们需要0表示成功状态才能&&正常工作。反之亦然(取决于你看到 时的反应有多强烈!=):

for file in * ; do awk 'NR==3{exit}END{exit NR==2}' "$file" || cp "$file" /tmp; done

答案2

您可以在线使用awk, (规则仍然执行),如果没有,则可以在块中使用 , 。行数不是例如:exit3ENDexit 1END2zsh

print -rl -- *(.e_'awk "NR==3{exit}END{if(NR!=2){exit 1}}" $REPLY'_)

将列出当前目录中的两行文件;如果您想移动它们,请替换print -rlmv并添加目的地。
与其他外壳:

for file in ./*; do [[ -f $file ]] && \
awk 'NR==3{exit};END{if(NR!=2){exit 1}}' "$file" && mv "$file" "$dest"
done

其他方式,例如使用zshell
格努 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"

相关内容