特定の行数のファイルのみをリスト(または移動)しますか?

特定の行数のファイルのみをリスト(または移動)しますか?

複数の2行構成ファイルを使用して作業するときに、行数が異なるすべてのファイルを除外する方法が必要です。

したがって、次のようになります。

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==33行目に遭遇すると、確認を使用して追加の処理を中止できることです。

NR!=2awkistrue/false値が面白いようですが、これが正しく機能するためには、1/0シェルで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'_)

現在のディレクトリにある2行のファイルが一覧表示されます。そのファイルを移動するには、ターゲットを置き換えて追加します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シェルを使用するなどの他の
方法ゲヌ awk:

awk 'ENDFILE{if(FNR==2){print FILENAME}}' ./*(.)

またはゲヌ sed(動詞4.2.2またはそれ以降):

sed -ns '2{$F}' ./*(.)

ファイル1と例を2行にリストします。

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] ' 

^このコマンドは、現在のディレクトリと2行のみを含むすべての直系サブディレクトリにあるドット以外のすべてのファイルを一覧表示します。

uniqglobはすでにソートされているので、実際にソートを心配する必要はありません。 3番目の入力行で終了するのは-m最後まで続くよりもはるかに高速なので、GNU axe一致オプションを使用しますが、このオプションなしで動作します。grepアイデアは、grep含まれている各行のファイル名を印刷してから、出力に各ファイル名が表示される回数を数え、2より大きいか小さいものをフィルタリングすることです。

私はこれをランダムなソースコードディレクトリに対して実行し、それらの両方には2行しか含まない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"

関連情報