最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux使用cut命令提取文本列的方法詳解

 更新時間:2026年06月05日 08:49:19   作者:知遠漫談  
在日常的?Linux?系統(tǒng)管理和數(shù)據(jù)處理工作中,我們經(jīng)常需要從結(jié)構(gòu)化的文本文件中提取特定字段,這時,cut?命令就成為了一把鋒利的小刀,能夠精準切割出我們需要的那一列或幾列內(nèi)容,本文將帶你全面掌握?cut?命令的使用方法,需要的朋友可以參考下

引言

在日常的 Linux 系統(tǒng)管理和數(shù)據(jù)處理工作中,我們經(jīng)常需要從結(jié)構(gòu)化的文本文件中提取特定字段。比如日志分析、CSV 數(shù)據(jù)清洗、系統(tǒng)用戶信息篩選等場景。這時,cut 命令就成為了一把鋒利的小刀,能夠精準“切割”出我們需要的那一列或幾列內(nèi)容。

本文將帶你全面掌握 cut 命令的使用方法,涵蓋其基本語法、高級技巧、常見誤區(qū),并通過 Java 代碼示例進行功能對比,幫助你理解不同工具在文本列提取任務中的優(yōu)劣與適用場景。文章最后還將提供性能對比圖表和實際應用場景建議,讓你不僅會用,更能用得高效、用得聰明!

什么是 cut 命令?

cut 是一個標準的 Unix/Linux 工具,屬于 GNU coreutils 包的一部分。它的核心作用是從每一行中“剪切”出指定的部分——可以是字節(jié)、字符或字段(列)。它輕量、快速、無依賴,在腳本自動化中廣泛使用。

提示:cut 默認按行處理輸入,每行獨立操作,非常適合結(jié)構(gòu)化文本(如 CSV、TSV、/etc/passwd 等)。

基本語法結(jié)構(gòu)

cut [選項] [文件...]

常用選項:

  • -b, --bytes=LIST:按字節(jié)位置提取
  • -c, --characters=LIST:按字符位置提取
  • -f, --fields=LIST:按字段(列)提取,默認以制表符 \t 分隔
  • -d, --delimiter=DELIM:自定義字段分隔符
  • --output-delimiter=STRING:設置輸出時字段之間的分隔符
  • -s, --only-delimited:僅輸出包含分隔符的行(用于過濾無效行)

其中最常用的是 -f-d 的組合。

按字段提取:-f 與 -d 的黃金搭檔

示例1:提取 /etc/passwd 中的用戶名和 shell

/etc/passwd 文件格式為冒號分隔的七列:

用戶名:密碼占位符:UID:GID:描述:家目錄:登錄Shell

我們想提取第一列(用戶名)和第七列(Shell):

cut -d ':' -f 1,7 /etc/passwd

輸出示例:

root:/bin/bash
daemon:/usr/sbin/nologin
bin:/usr/sbin/nologin
sys:/usr/sbin/nologin
...

注意:-d 后面緊跟分隔符,必須是單個字符(不能是字符串),如需多字符分隔,請結(jié)合 awk 或其他工具。

示例2:提取 CSV 文件中的姓名和郵箱

假設有一個 users.csv

ID,Name,Email,Department
1,Alice,alice@example.com,Engineering
2,Bob,bob@example.com,Sales
3,Carol,carol@example.com,Marketing

我們想提取 Name 和 Email(第2、3列):

cut -d ',' -f 2,3 users.csv

輸出:

Name,Email
Alice,alice@example.com
Bob,bob@example.com
Carol,carol@example.com

字段范圍與復雜選擇

cut 支持靈活的字段選擇語法:

  • N:第 N 列
  • N-M:從第 N 到第 M 列(閉區(qū)間)
  • N-:從第 N 列到行尾
  • -M:從開頭到第 M 列
  • N,M,K:多個不連續(xù)列

示例3:提取第2列到最后一列

cut -d ',' -f 2- users.csv

輸出:

Name,Email,Department
Alice,alice@example.com,Engineering
Bob,bob@example.com,Sales
Carol,carol@example.com,Marketing

示例4:提取第1、3、5列(跳過中間)

cut -d ',' -f 1,3,5 data.txt

注意:如果某行列數(shù)不足,缺失列會被忽略,不會報錯。這既是優(yōu)點(容錯),也是缺點(可能漏數(shù)據(jù))。

按字符/字節(jié)提?。?c 與 -b

有時我們面對的是固定寬度的文本(如舊式日志、Fortran 輸出等),這時可以按字符位置提取。

示例5:提取每行前10個字符

cut -c 1-10 logfile.txt

示例6:提取第5到第15字節(jié)(注意:對多字節(jié)字符如中文可能截斷?。?/h3>
cut -b 5-15 unicode.txt

重要區(qū)別:

  • -c 按“字符”計數(shù),適合 UTF-8 等多字節(jié)編碼
  • -b 按“字節(jié)”計數(shù),可能破壞多字節(jié)字符結(jié)構(gòu)

推薦在處理 Unicode 文本時優(yōu)先使用 -c

過濾無效行:-s 選項

當使用 -f 時,如果某行不含分隔符,則整行原樣輸出(除非使用 -s)。

示例7:只輸出含逗號的行

cut -d ',' -f 2 -s messy.csv

適用于清理格式混亂的數(shù)據(jù)文件。

自定義輸出分隔符:–output-delimiter

默認情況下,cut 輸出字段仍使用原分隔符。你可以用 --output-delimiter 替換它。

示例8:用豎線代替逗號輸出

cut -d ',' -f 2,3 --output-delimiter=' | ' users.csv

輸出:

Name | Email
Alice | alice@example.com
Bob | bob@example.com
Carol | carol@example.com

非常實用在生成報表或?qū)肫渌到y(tǒng)時調(diào)整格式。

常見陷阱與注意事項

1. 分隔符只能是單字符

# ? 錯誤:cut 不支持多字符分隔符
cut -d '::' -f 2 file.txt

# ? 正確:先用 sed/awk 替換,再 cut
sed 's/::/:/g' file.txt | cut -d ':' -f 2

2. 字段編號從1開始

# ? 錯誤
cut -f 0,1 file.txt

# ? 正確
cut -f 1,2 file.txt

3. 空字段處理

如果某列為空,cut 仍會保留其位置:

a,,c,d

執(zhí)行 cut -d ',' -f 2 將輸出空行(不是跳過)。

4. 不支持正則表達式

cut 是純文本定位工具,無法像 awk 那樣基于模式匹配列。

實戰(zhàn)演練:日志字段提取

假設你有如下 Nginx 訪問日志(簡化版):

192.168.1.1 - - [10/Oct/2023:13:55:36 +0000] "GET /index.html HTTP/1.1" 200 612
192.168.1.2 - - [10/Oct/2023:13:55:40 +0000] "POST /login HTTP/1.1" 302 0

目標:提取 IP、請求方法、狀態(tài)碼

由于空格不是可靠分隔符(URL 中可能含空格),更推薦用 awk,但若格式固定,也可嘗試:

cut -d ' ' -f 1,6,9 access.log

輸出:

192.168.1.1 "GET 200
192.168.1.2 "POST 302

不夠理想?那就該換 awk 了:

awk '{print $1, $6, $9}' access.log

結(jié)論:cut 適合結(jié)構(gòu)清晰、分隔符明確的文本;復雜結(jié)構(gòu)請用 awkperl。

性能表現(xiàn)如何?—— 與 awk/sed 對比

雖然 cut 功能有限,但它在簡單任務中速度極快,因為其實現(xiàn)非常輕量。

我們做一個簡單測試(百萬行數(shù)據(jù)):

# 生成測試數(shù)據(jù)
seq 1 1000000 | awk '{print $1","$1*2","$1*3","$1*4}' > test.csv

# 測試 cut
time cut -d ',' -f 2,4 test.csv > /dev/null

# 測試 awk
time awk -F',' '{print $2,$4}' OFS=',' test.csv > /dev/null

通常 cut 會比 awk 快 2~5 倍,尤其在 SSD 上差異更明顯。

Java 實現(xiàn)對比:自己寫“cut”

既然 cut 如此常用,我們能否用 Java 實現(xiàn)類似功能?當然可以!下面是一個簡化版的 Java Cut 工具類。

import java.io.*;
import java.util.*;
import java.nio.file.*;
public class JavaCut {
    public static void main(String[] args) throws IOException {
        if (args.length < 3) {
            System.err.println("Usage: java JavaCut <delimiter> <fields> <file>");
            System.err.println("Example: java JavaCut , 1,3 data.csv");
            return;
        }
        String delimiter = args[0];
        String fieldSpec = args[1];
        String filename = args[2];
        List<Integer> fields = parseFieldSpec(fieldSpec);
        processFile(filename, delimiter, fields);
    }
    private static List<Integer> parseFieldSpec(String spec) {
        List<Integer> fields = new ArrayList<>();
        for (String part : spec.split(",")) {
            if (part.contains("-")) {
                String[] range = part.split("-");
                int start = Integer.parseInt(range[0]);
                int end = range.length > 1 ? Integer.parseInt(range[1]) : Integer.MAX_VALUE;
                for (int i = start; i <= end && i <= 1000; i++) { // 防止無限循環(huán)
                    fields.add(i);
                }
            } else {
                fields.add(Integer.parseInt(part));
            }
        }
        return fields;
    }
    private static void processFile(String filename, String delimiter, List<Integer> fields) throws IOException {
        try (BufferedReader reader = Files.newBufferedReader(Paths.get(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] tokens = line.split(delimiter, -1); // 保留尾部空字段
                List<String> selected = new ArrayList<>();
                for (int index : fields) {
                    if (index > 0 && index <= tokens.length) {
                        selected.add(tokens[index - 1]); // Java 數(shù)組從0開始
                    }
                }
                System.out.println(String.join(delimiter, selected));
            }
        }
    }
}

編譯運行:

javac JavaCut.java
java JavaCut , 2,4 test.csv

這個 Java 版本支持:

  • 自定義分隔符
  • 字段范圍(如 2-4
  • 多字段選擇(如 1,3,5
  • 保留空字段

功能對比:Linux cut vs Java Cut

功能Linux cutJava Cut 實現(xiàn)
按字段提取??
按字符/字節(jié)提取??(可擴展)
自定義輸出分隔符??
僅輸出含分隔符的行? (-s)?
多字符分隔符??(split 支持)
處理超大文件(流式)??
跨平臺?(需安裝)?
Unicode 安全? (-c)?

選擇建議:

  • 簡單、快速、腳本中 → 用 cut
  • 需要復雜邏輯、跨平臺、集成到應用 → 用 Java 實現(xiàn)
  • 多字符分隔、正則匹配 → 用 awk

性能對比圖表(百萬行數(shù)據(jù))

下面我們用 Mermaid 圖表展示在不同數(shù)據(jù)規(guī)模下,cut 與 Java 實現(xiàn)的耗時對比。

從圖中可見,cut 在各數(shù)據(jù)規(guī)模下均顯著快于 Java 實現(xiàn),尤其在百萬行級別差距達 3 倍。這是因為:

  • cut 是 C 編寫,直接系統(tǒng)調(diào)用,無 JVM 啟動開銷
  • Java 需要對象創(chuàng)建、GC、UTF 解碼等額外成本
  • cut 內(nèi)部優(yōu)化極致,逐字符處理無緩沖復制

高級技巧:cut 與其他命令組合

cut 很少單獨使用,常作為管道中的一環(huán)。

技巧1:排序去重后提取

cat data.csv | sort | uniq | cut -d ',' -f 1

技巧2:結(jié)合 grep 過濾后提取

grep "ERROR" app.log | cut -d ' ' -f 1,4

技巧3:統(tǒng)計某列唯一值數(shù)量

cut -d ',' -f 3 users.csv | sort | uniq -c | sort -nr

輸出示例:

  45 Engineering
  32 Sales
  18 Marketing

技巧4:提取列后重新組合成新格式

cut -d ',' -f 1,3 users.csv | sed 's/,/ -> /'

輸出:

1 -> alice@example.com
2 -> bob@example.com
3 -> carol@example.com

實際應用場景推薦

場景1:系統(tǒng)監(jiān)控腳本

#!/bin/bash
# 監(jiān)控高負載進程,提取 PID 和 COMMAND
ps aux --sort=-%cpu | head -10 | tail -n +2 | cut -c 10-15,68-

場景2:API 日志分析

# 提取訪問最頻繁的 endpoint
cut -d ' ' -f 7 access.log | sort | uniq -c | sort -nr | head -5

場景3:數(shù)據(jù)庫導出數(shù)據(jù)清洗

# 從 mysqldump 中提取表名
grep "^CREATE TABLE" dump.sql | cut -d '`' -f 2

Java 增強版:支持更多特性

前面的 Java Cut 是基礎版,下面我們實現(xiàn)一個增強版本,支持:

  • -s 類似行為(跳過無分隔符行)
  • 多字符分隔符(使用正則)
  • 輸出分隔符自定義
  • 字符位置提?。M -c
import java.io.*;
import java.util.*;
import java.nio.file.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class JavaCutPro {
    private static class Options {
        String delimiter = "\\s+"; // 默認空白分隔
        String outputDelimiter = "\t";
        List<Integer> fields = new ArrayList<>();
        boolean onlyDelimited = false;
        boolean byChar = false;
        String charRange = "";
    }
    public static void main(String[] args) throws IOException {
        Options opts = parseArgs(args);
        if (opts == null) return;
        Path file = Paths.get(args[args.length - 1]);
        processFile(file, opts);
    }
    private static Options parseArgs(String[] args) {
        if (args.length < 2) {
            printUsage();
            return null;
        }
        Options opts = new Options();
        int i = 0;
        while (i < args.length - 1) {
            switch (args[i]) {
                case "-d":
                    opts.delimiter = args[++i];
                    break;
                case "-f":
                    opts.fields = parseFieldSpec(args[++i]);
                    break;
                case "--output-delimiter":
                    opts.outputDelimiter = args[++i];
                    break;
                case "-s":
                    opts.onlyDelimited = true;
                    break;
                case "-c":
                    opts.byChar = true;
                    opts.charRange = args[++i];
                    break;
                default:
                    System.err.println("Unknown option: " + args[i]);
                    return null;
            }
            i++;
        }
        if (opts.fields.isEmpty() && !opts.byChar) {
            System.err.println("Must specify -f or -c");
            return null;
        }
        return opts;
    }
    private static void processFile(Path file, Options opts) throws IOException {
        try (BufferedReader reader = Files.newBufferedReader(file)) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (opts.byChar) {
                    processByChar(line, opts.charRange);
                } else {
                    processByField(line, opts);
                }
            }
        }
    }
    private static void processByField(String line, Options opts) {
        String[] tokens = line.split(opts.delimiter, -1);
        // 如果啟用 -s 且沒有分隔符(即只有一列),跳過
        if (opts.onlyDelimited && tokens.length <= 1) {
            return;
        }
        List<String> selected = new ArrayList<>();
        for (int index : opts.fields) {
            if (index > 0 && index <= tokens.length) {
                selected.add(tokens[index - 1]);
            }
        }
        if (!selected.isEmpty()) {
            System.out.println(String.join(opts.outputDelimiter, selected));
        }
    }
    private static void processByChar(String line, String rangeSpec) {
        List<int[]> ranges = parseCharRanges(rangeSpec);
        StringBuilder sb = new StringBuilder();
        for (int[] range : ranges) {
            int start = range[0] - 1; // 轉(zhuǎn)為0基
            int end = range[1];
            if (start < line.length()) {
                int actualEnd = Math.min(end, line.length());
                sb.append(line.substring(start, actualEnd)).append(" ");
            }
        }
        if (sb.length() > 0) {
            System.out.println(sb.toString().trim());
        }
    }
    private static List<int[]> parseCharRanges(String spec) {
        List<int[]> ranges = new ArrayList<>();
        for (String part : spec.split(",")) {
            if (part.contains("-")) {
                String[] ends = part.split("-");
                int start = Integer.parseInt(ends[0]);
                int end = ends.length > 1 ? Integer.parseInt(ends[1]) : start;
                ranges.add(new int[]{start, end});
            } else {
                int pos = Integer.parseInt(part);
                ranges.add(new int[]{pos, pos});
            }
        }
        return ranges;
    }
    private static List<Integer> parseFieldSpec(String spec) {
        List<Integer> fields = new ArrayList<>();
        for (String part : spec.split(",")) {
            if (part.contains("-")) {
                String[] range = part.split("-");
                int start = Integer.parseInt(range[0]);
                int end = range.length > 1 ? Integer.parseInt(range[1]) : Integer.MAX_VALUE;
                for (int i = start; i <= end && i <= 1000; i++) {
                    fields.add(i);
                }
            } else {
                fields.add(Integer.parseInt(part));
            }
        }
        return fields;
    }
    private static void printUsage() {
        System.err.println("Usage: java JavaCutPro [OPTIONS] FILE");
        System.err.println("Options:");
        System.err.println("  -d DELIM          Field delimiter (regex)");
        System.err.println("  -f FIELDS         Comma-separated field numbers (e.g., 1,3-5)");
        System.err.println("  -c RANGES         Character ranges (e.g., 1-10,15-20)");
        System.err.println("  --output-delimiter OUTPUT_DELIM");
        System.err.println("  -s                Suppress lines with no delimiter");
    }
}

這個增強版幾乎可以替代日常使用的 cut,并額外支持:

  • 正則分隔符(如 \s+ 匹配任意空白)
  • 字符位置提取
  • 更靈活的范圍語法

測試你的理解:小測驗

試著預測以下命令的輸出:

Q1: echo "apple,banana,cherry,date" | cut -d ',' -f 2-

Q2: echo "hello world" | cut -c 3-7

Q3: printf "a:b:c\nx:y\np\n" | cut -d ':' -f 2 -s

A1: banana,cherry,date
A2: llo w
A3: 只輸出 by(第三行被 -s 過濾)

總結(jié)與最佳實踐

cut 是 Linux 文本處理生態(tài)中不可或缺的基礎工具。雖然功能簡單,但在合適場景下效率極高。以下是使用建議:

何時用 cut:

  • 分隔符明確且為單字符
  • 只需提取固定列,無復雜條件
  • 追求極致性能(尤其大文件)
  • 在 Shell 腳本中作為管道組件

何時不用 cut:

  • 分隔符是字符串或正則表達式
  • 需要條件判斷、計算、格式轉(zhuǎn)換
  • 處理嵌套結(jié)構(gòu)或非結(jié)構(gòu)化文本
  • 需要跨平臺一致性(Windows 無原生 cut)

最佳實踐:

  1. 始終明確分隔符,避免默認 \t 導致錯誤
  2. 使用 -s 清理臟數(shù)據(jù)
  3. --output-delimiter 控制輸出格式
  4. 復雜任務交給 awk —— “瑞士軍刀”更適合多功能需求
  5. 百萬行以上數(shù)據(jù)優(yōu)先考慮 cut 而非腳本語言實現(xiàn)

結(jié)語

掌握 cut 命令,就像程序員掌握了數(shù)組索引——看似基礎,卻是構(gòu)建復雜數(shù)據(jù)流水線的基石。配合 grep、sort、uniq、awk 等工具,你可以在命令行完成絕大多數(shù)數(shù)據(jù)預處理任務,無需啟動笨重的 IDE 或數(shù)據(jù)庫。

希望本文不僅教會你 cut 的用法,更啟發(fā)你思考:在正確的場景選擇正確的工具,才是高效工作的本質(zhì)。

以上就是Linux使用cut命令提取文本列的方法詳解的詳細內(nèi)容,更多關(guān)于Linux cut提取文本列的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • shell實現(xiàn)貪吃蛇的示例代碼

    shell實現(xiàn)貪吃蛇的示例代碼

    本文主要介紹了shell實現(xiàn)貪吃蛇的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • Bash Shell字符串操作小結(jié)

    Bash Shell字符串操作小結(jié)

    這篇文章主要介紹了Bash Shell字符串操作總結(jié),包含取長度、截取、查找位置、替換等等,需要的朋友可以參考下
    2014-05-05
  • linux上配置jdk時,java命令提示沒有此文件或文件夾的解決方法

    linux上配置jdk時,java命令提示沒有此文件或文件夾的解決方法

    下面小編就為大家?guī)硪黄猯inux上配置jdk時,java命令提示沒有此文件或文件夾的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Shell編程基礎語法與正則表達式文本處理指南

    Shell編程基礎語法與正則表達式文本處理指南

    本文詳解Shell編程與正則表達式在Linux系統(tǒng)中的應用,涵蓋函數(shù)、數(shù)組、grep工具及實戰(zhàn)案例,建議深入學習文本處理三劍客和正則進階技巧,提升系統(tǒng)管理效率,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • 詳解kali linux 常用文件與指令路徑

    詳解kali linux 常用文件與指令路徑

    這篇文章主要介紹了kali linux 常用文件與指令路徑,文中給大家介紹了Linux下MySQL忘記root密碼的完美解決方法,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-07-07
  • bash shell獲取當前腳本的絕對路徑(pwd/readlink)

    bash shell獲取當前腳本的絕對路徑(pwd/readlink)

    有時候,我們需要知道當前執(zhí)行的輸出shell腳本的所在絕對路徑,本文主要介紹了bash shell獲取當前腳本的絕對路徑,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Linux 中LVS NAT 配置步驟的詳解

    Linux 中LVS NAT 配置步驟的詳解

    這篇文章主要介紹了Linux 中LVS NAT 配置步驟的詳解的相關(guān)資料,這里列出詳細的實現(xiàn)步驟,需要的朋友可以參考下
    2017-08-08
  • Linux命令行和shell腳本編程寶典 Richard Blum

    Linux命令行和shell腳本編程寶典 Richard Blum

    Linux命令行和shell腳本編程寶典,主要介紹了linux一些命令的使用
    2012-09-09
  • Shell腳本美化登錄界面裝飾圖(含農(nóng)歷)

    Shell腳本美化登錄界面裝飾圖(含農(nóng)歷)

    這篇文章主要介紹了Shell腳本美化登錄界面裝飾圖(含農(nóng)歷),本文腳本實現(xiàn)輸出一個佛祖像和農(nóng)歷日期,需要的朋友可以參考下
    2015-02-02
  • 淺析Linux中重定向問題

    淺析Linux中重定向問題

    這篇文章主要介紹了淺析Linux中重定向問題,需要的朋友可以參考下
    2017-08-08

最新評論

长汀县| 涞源县| 镇坪县| 舟曲县| 克东县| 绥化市| 连城县| 南丰县| 永寿县| 永靖县| 太仆寺旗| 河南省| 北碚区| 三都| 延长县| 吕梁市| 甘谷县| 县级市| 钟祥市| 东阳市| 海淀区| 德惠市| 尼玛县| 紫阳县| 诸城市| 休宁县| 中阳县| 九台市| 定州市| 南澳县| 福建省| 石棉县| 滨州市| 翼城县| 皮山县| 达州市| 嘉义市| 万宁市| 科尔| 周口市| 探索|