情景linux--如何得出一個文件的第二列?

情景

曾經有一同事問我,在linux下如何輸出一個文本文件的第二列,文本內容不限。我不假思索地說用awk啊。她追問只有這一種方式么?于是我仔細想了想,……

分析

既然內容不限,則可以自定義文件內容的格式,這樣可以用的命令自然會多一些。

需求為輸出文件第二列,則基本上有兩種方式實現:

  • 直接過濾第二列并輸出;
  • 將其他列刪除,只剩下第二列;

因而,任何能直接輸出特定列的命令,以及能夠截取或刪除其它列的命令都滿足此需求。

示例文件

為了方便說明,列舉幾個示例文件:

cat test1.txt 
1 zhangsan 15 hebei
2 lisi 17 jiangsu
3 wangwu 29 tianjin
4 zhaoliu 21 fujian
cat test2.txt 
1:test001:15:hebei
2:test002:17:jiangsu
3:test003:29:tianjin
4:test004:21:fujian

方案

awk

awk自然是最容易想到的,它處理格式化的文本得心應手。

awk '{print $2}' test1.txt
zhangsan
lisi
wangwu
zhaoliu

使用-F指定列(字段)分隔符。

awk -F ":" '{print $2}' test2.txt
test001
test002
test003
test004

如果文件只有兩列,還可以使用$NF,如awk '{print $NF}' test1.txt

awk還支持一些函數,同樣可以將第二列提取出來,此處不再贅述。

cut

cut命令的默認字段分隔符是TAB,可以使用-d重新指定。 -f列出指定字段。

cut -d " " -f 2 test1.txt
zhangsan
lisi
wangwu
zhaoliu
cut -d ":" -f 2 test2.txt 
test001
test002
test003
test004

如果第二列的字符的起始和結束序號為固定值,如test2.txt,可以使用-c參數,截取特定的字符序列。

cut -c 3-9 test2.txt
test001
test002
test003
test004

sed

sed采用的是第二種實現方式,即將其它列刪除掉,利用后向引用

sed "s/^[^ ]* \([^ ]*\) [^ ]* [^ ]*/\1/g" test1.txt 
zhangsan
lisi
wangwu
zhaoliu
sed "s/^[^:]*:\([^:]*\):[^:]*:[^:]*/\1/g" test2.txt
test001
test002
test003
test004

grep

在test1.txt中,第二列的前面和后面分別為數字空格和空格數字,所以可以利用正則表達式將其輸出出來。

grep -oP "(?<=[0-9] )[^ ]+(?= [0-9])" test1.txt
zhangsan
lisi
wangwu
zhaoliu

同理:

grep -oP "(?<=[0-9]:)[^:]+(?=:[0-9])" test2.txt 
test001
test002
test003
test004

colrm

colrm命令可以刪除標準輸入中的指定列,但該命令中所定義的列指的是單個字符,這與常規對字段的定義不同,需注意。
格式如下:

colrm [start [stop]]

如果只指定start,則大于等于start的列均被刪除;如果指定了start和stop,則大于等于start,小于等于stop的列被刪除。

因此,此命令可處理第二個字段起始位置為固定值的test2.txt文件。

cat test2.txt | colrm 1 2 | colrm 8

test001
test002
test003
test004

read

read讀取文件中的每行,將特定的列輸出來。

while read a b c d ;do echo $b;done < test1.txt 
zhangsan
lisi
wangwu
zhaoliu
IFS=":";while read a b c d ;do echo $b;done < test2.txt
test001
test002
test003
test004

shell命令替換

shell支持命令替換,通過兩次命令替換,得到第二列:

while read line;do temp1=${line#* };temp2=${temp1%% *};echo $temp2; done < test1.txt
zhangsan
lisi
wangwu
zhaoliu
while read line;do temp1=${line#*:};temp2=${temp1%%:*};echo $temp2; done < test2.txt
test001
test002
test003
test004

總結

雖然不清楚她從哪里看到的這道題目,題目本身是何用意。但以一個問題,調動起了對linux多個命令及知識點的學習和總結,還是有價值的。

歡迎提出不同解法!

相關命令

  • awk
  • cut
  • grep
  • sed
  • colrm
  • read
  • shell命令替換
  • 后向引用
  • 正則表達式
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數據革命閱讀 12,239評論 2 33
  • 基礎命令 主要的命令和快捷鍵 Linux系統命令由三部分組成:cmd + [options]+[operation...
    485b1aca799e閱讀 1,125評論 0 0
  • 本文承接之前寫的三十分鐘學會AWK一文,在學習完AWK之后,趁熱打鐵又學習了一下SED,不得不說這兩個工具真的堪稱...
    mylxsw閱讀 4,417評論 3 74
  • sed與awk實例 文本間隔 在每一行后面增加一空行 將原來的所有空行刪除并在每一行后面增加一空行。這樣在輸出的文...
    stuha閱讀 1,921評論 0 21
  • 轉載 原文的排版和內容都更加友好,并且詳細,我只是在這里貼出了一部分留作自己以后參考和學習,如希望更詳細了解AWK...
    XKirk閱讀 3,276評論 2 25