簡體   English   中英

基於bash中特定列的排序錯誤

[英]Error in sorting based on a specific column in bash

嗨,我正在嘗試這個東西,但它不起作用。 在此處輸入圖像描述

我知道它不起作用,因為當單詞用空格分隔時,每行都有不同的列數,但是我們可以以任何方式完成預期的工作。

注意:假設輸入文件的列由空格而不是制表符分隔,否則 dan 的注釋 - sort -nt $'\t' -k3,3 - 就足夠了


sort允許我們指定字段終止符以及要排序的字段(以及可選的字段子字符串)。

如果我們將字段分隔符設置為換行符 ( \n ),則整行將變為單個字段。

從這里我們可以指定字段 #1 的子字符串作為排序依據; -k1.x,1.y表示按字段 #1 從位置x到位置y排序(字段/行的第一個字符的位置為1 )。

樣本輸入:

$ cat animals.txt
         1         2         3         4         5         6
123456789012345678901234567890123456789012345678901234567890
alpaca   Intermediate Perl         2012   Schwatz, Randal
donkey   Cisco IOS in a Nutshell   2005   Boney, James
horse    Linux in a Nutshell       2009   Siever, Ellen

在哪里:

  • 文件中不存在前 2 行(比例); 規模向我們展示...
  • 行的year部分從位置3639

將所有這些都放入一個sort調用中:

# sort numerically by year (ascending)

$ sort -t$'\n' -k1.36,1.39 -n animals.txt
donkey   Cisco IOS in a Nutshell   2005   Boney, James
horse    Linux in a Nutshell       2009   Siever, Ellen
alpaca   Intermediate Perl         2012   Schwatz, Randal

# sort numerically by year (descending)

$ sort -t$'\n' -k1.36,1.39 -rn animals.txt
alpaca   Intermediate Perl         2012   Schwatz, Randal
horse    Linux in a Nutshell       2009   Siever, Ellen
donkey   Cisco IOS in a Nutshell   2005   Boney, James

注意:假設所有行的year都在同一位置(即文件的內容按照固定寬度方案進行格式化)

顯然這種方法需要我們提前知道year子串的位置; 有幾種方法可以確定這個位置......一個想法,假設year列總是第一次出現 4 位子字符串......使用bash正則表達式匹配和BASH_REMATCH[]數組來確定排列到 4 位數的year ,例如:

$ regex="^([^0-9]*)([0-9]{4}).*"
$ [[ $(head -1 animals.txt) =~ $regex ]] && typeset -p BASH_REMATCH
declare -ar BASH_REMATCH=([0]="alpaca   Intermediate Perl         2012   Schwatz, Randal" [1]="alpaca   Intermediate Perl         " [2]="2012")

從這里我們看到BASH_REMATCH[1]包含該行的內容,直到year2012用於alpaca行); 現在我們獲取BASH_REMATCH[1]的長度並添加 +1/+3 以獲得我們的xy值:

$ (( x = ${#BASH_REMATCH[1]} + 1 ))
$ (( y = x + 3 ))
$ typeset -p x y
declare -- x="36"
declare -- y="39"

將這些變量插入到我們之前的sort調用中:

# sort numerically by year (ascending)

$ sort -t$'\n' -k1.${x},1.${y} -n animals.txt
donkey   Cisco IOS in a Nutshell   2005   Boney, James
horse    Linux in a Nutshell       2009   Siever, Ellen
alpaca   Intermediate Perl         2012   Schwatz, Randal

# sort numerically by year (descending)

$ sort -t$'\n' -k1.${x},1.${y} -rn animals.txt
alpaca   Intermediate Perl         2012   Schwatz, Randal
horse    Linux in a Nutshell       2009   Siever, Ellen
donkey   Cisco IOS in a Nutshell   2005   Boney, James

注意:在多行具有相同日期的情況下,OP 沒有定義二級排序要求,但擴展這個答案以包括二級(和三級?)排序要求應該不會太難

嘗試添加逗號之類的分隔符,因為從那里您將能夠使用帶有-t參數的sort命令並指定給定的字段分隔符。

要查找並用分隔符替換字符,我會使用cat animals.txt | sed {insert the pattern} cat animals.txt | sed {insert the pattern}

根據您共享的文件,您可以嘗試在第一個單詞之后以及數值之前和之后添加分隔符。

注意:假設輸入文件的列由空格而不是制表符分隔,否則 dan 的注釋 - sort -nt $'\t' -k3,3 - 就足夠了


如果GNU awk可用,我們可以讓awk找到year子字符串的索引,然后為我們對輸出進行排序。

樣本輸入:

$ cat animals.txt
         1         2         3         4         5         6
123456789012345678901234567890123456789012345678901234567890
alpaca   Intermediate Perl         2012   Schwatz, Randal
donkey   Cisco IOS in a Nutshell   2005   Boney, James
horse    Linux in a Nutshell       2009   Siever, Ellen

在哪里:

  • 文件中不存在前 2 行(比例); 規模向我們展示...
  • 行的year部分從位置3639

一個GNU awk想法:

awk '
FNR==1 { x=match($0, /[0-9]{4}/) }                # find index of the "year" substring in the 1st line of input; assumes the "year" is the 1st occurrence of a 4-digit substring
       { arr[substr($0,x,4)][FNR]=$0 }            # populate 2-dimensional array using "year" and row number (FNR) as indexes
END    { PROCINFO["sorted_in"]="@ind_num_asc"     # sort indexes as numbers in "asc"ending order
         for (i in arr)
             for (j in arr[i])
                 print arr[i][j]
       }
' animals.txt

這會產生:

donkey   Cisco IOS in a Nutshell   2005   Boney, James
horse    Linux in a Nutshell       2009   Siever, Ellen
alpaca   Intermediate Perl         2012   Schwatz, Randal

如果我們將排序順序從@ind_num_asc更改為@ind_num_desc ,我們可以按year降序生成輸出,即:

alpaca   Intermediate Perl         2012   Schwatz, Randal
horse    Linux in a Nutshell       2009   Siever, Ellen
donkey   Cisco IOS in a Nutshell   2005   Boney, James

筆記:

  • 多維數組(又名數組數組)支持所需的GNU awk
  • PROCINFO["sorted_in"]功能需要GNU awk
  • 假設整個文件可以放入內存(由於將所有行都存儲在數組中)

一種方法是使用sed將年份復制到每行的開頭,對結果輸出進行數字sort ,然后在每行的開頭刪除年份:

sed 's/^.*[[:space:]]\([12][09][0-9][0-9]\)[[:space:]].*$/\1 &/' animals.txt \
    | sort -n | sed 's/^.....//'

問題中帶有示例animals.txt的輸出是:

oryx    Writing Word Macros     1999    Roman, Steven
donkey  Cisco IOS in a Nutshell 2005    Boney, James
snail   SSH, The Secure Shell   2005    Barrett, Daniel
horse   Linux in a Nutshell     2009    Sievers, Ellen
python  Programming Python      2010    Lutz, Mark
alpaca  Intermediate Perl       2012    Schwartz, Randal
robin   MySQL High Availability 2014    Bell, Charles

暫無
暫無

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

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