簡體   English   中英

使用awk或sed比較多個文件的長度

[英]compare the length of multiple files using awk or sed

我想比較每個文件的行數,然后選擇包含最大行數的文件,例如

filename_V1 |wc -l =100
filename_V2 |wc -l =19
filename_V3  |wc -l =10

myFile_V1  |wc -l =1
myFile_V2  |wc -l =10
myFile_V3  |wc -l =15

我會得到結果

filename_V1
myFile_V3

這是一種將考慮按其基本部分(在_Vn之前)分組的文件,並打印_Vn最多的文件。

編輯 :只是指出,如果某些文件名包含空格,則awk腳本不合適(它假定wc輸出中的第二個字段是整個文件名)。

$ cat bf.awk
$2 ~ /_V[0-9]+/ {
    lines = $1;
    file = $2;
    base = file;
    sub("_.*", "", base);
    if (lines > max[base]) {
        max[base] = lines;
        best[base] = file;
    }
}

END { for (base in best) print best[base] }


$ wc -l *_V*
       3 a_V1
       1 a_V2
       4 a_V3
       4 b_V1
       3 b_V2
       1 b_V3
       2 b_V4
      18 total


$ wc -l *_V* | awk -f bf.awk
a_V3
b_V1
wc -l filename_V1 filename_V2 filename_V3 myFile_V1 myFile_V2 myFile_V3 | \
sort -rg

“每個文件的行數” | “按數字排序” | “逆序”

它還會打印總數(應該是最大數量),但這對您來說應該足夠了。

這是單線的。 我使用\\分隔符使其更清晰

混合:

command_that_spits_files | xargs wc -l | sort -rg
find . -name 'filename_V[0-9]\{1,2\}' | xargs -L1 wc -l | sort -rg | cut -d ' ' -f 2

如果您不想sort ,則可以使用awk查找最大值,因為它還會報告行數,而不僅是最長文件的名稱(按行數)。

wc -l filename_v1 filename_v2 filename_v3 | awk '$2 != "total" {if($1 > max_val) {max_val=$1; max_file=$2}}0; END{print max_file}'

因此,我們將執行wc -l以獲取我們感興趣的任何文件集中的行數計數,然后在awk中,通過查看第一個值並跟蹤我們看到的最大行數,存儲它,然后最后只打印出與我們看到的最大行數關聯的文件名。

而且從好的方面來說,我們將不計算“總計”行

查找所有文件並執行此操作的最安全方法是執行以下操作(使用GNU wc):

find -type f -name '*_V*' -print0 | wc -l --files0-from=- | awk '$2 != "total" {if($1 > max_val) {max_val=$1; max_file=$2}}0; END{print max_file}'

或沒有GNU的wc:

find -type f -name '*_V*' -print0 | xargs -0 wc -l | awk '$2 != "total" {if($1 > max_val) {max_val=$1; max_file=$2}}0; END{print max_file}'

並在-name中為-name使用適當的文件glob。 另外,如果您不想查看子目錄,請添加-maxdepth 1

LARGESTFILE=;MAXLINECOUNT=0;for file in *; do CURRENTCOUNT=$(wc -l <"$file"); if [ "$CURRENTCOUNT" -gt "$MAXLINECOUNT" ]; then LARGESTFILE=$file; MAXLINECOUNT=$CURRENTCOUNT; fi; done; echo $LARGESTFILE

另一個“一個班輪”:

# generate a tab seperated table: name|basename|lines
for f in *_V[0-9]*;do printf "$f\t${f%V*}\t%d\n" $(wc -l < "$f");done |\
    sort -t$'\t' -k3rn    |\ # sort rows by line number descending
    sort -t$'\t' -u -k2,2 |\ # take rows with unique basename in sorted order
    cut -f1                  # take name column

這假定您的文件名中沒有制表符或換行符,並且使用了許多bashism( $轉義字符,字符串操作)。 與此處的大多數答案不同,它不會占用空格或文件名中多次出現_


更高效的版本

原始文件很健壯,但是生成表的時候調用了printfwc N次。 這個有點難看,但是速度要快得多(在我的機器上是200倍):

# table is now basename|lines|name
printf "%s\n" *_V[0-9]*           |\ # print every file on a new line
    rev | cut -d_ -f2- | rev      |\ # extract the base name (faster than sed)
    paste - \                        # combine base name and wc output
        <(wc -l *_V[0-9]* |\
        sed 's/^ *//;s/ /\t/;$d') |\ # tabulate wc output
    sort -t$'\t' -k2rn,2          |\ # sort as above
    sort -t$'\t' -u -k1,1         |\
    cut -f3

有很多管道的替代品

wc -l *_V* | \             # generate the list
sed 's/_V/ _V/;$d' | \     # separate baseline from versions, delete total
sort -k 2,2 -k 1,1nr | \   # sort by names and size (reverse)
sort -k 2,2 -u | \         # get the first by name (max by design)
sed 's/ _V/_V/' | \        # reverse baseline name back to original
awk '{print $2}'           # extract the filename

該腳本假定文件名在您的控制之下,並且基本名稱中不會出現空格或_V。 否則請檢查@Qualia的版本。

使用GNU awk的BEGINFILE:

awk '
BEGINFILE { base=FILENAME; sub(/_[^_]+$/,"",base); fname[base]; max=0 }
FNR > max { max=FNR; fname[base]=FILENAME }
END { for (base in fname) print fname[base] }
' *

您可以使用FNR==1而不是BEGINFILE在非gawk中進行近似BEGINFILE但是如果可能的話,您將需要額外的代碼來處理所有具有給定基數的文件為空的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM