awk 腳本中的管道

awk 腳本中的管道

我正在嘗試編寫一個ls包裝器,用於awk解析ls -lhF.現在我已將程式分成兩個檔案 -my_ls.shmy_ls.awk.my_ls.sh的唯一目的是ls -lhF將的輸出透過管道傳輸到my_ls.awk。看起來像:

#!/bin/bash
ls -lhF "$@" | my_ls.awk

ls -lhF我想知道是否有任何方法可以透過 awk 腳本本身讀取輸出。

編輯:我的主要目的是編寫一個腳本,以漂亮的樹的形式顯示當前目錄內容。的草稿版本my_ls.awk如下圖所示:

#!/usr/bin/awk -f

( NF >= 9 ) {
    print "|-- [" $5 "] " $9
}

這是我到目前為止所達到的目標。

答案1

我將加入其他建議,即您不應解析 的輸出ls,因此這是一個不好的例子。但作為更一般的問題,我將通過將 awk 腳本作為參數傳遞給awk.

#!/bin/bash
ls -lhF "$@" | awk '
    ( NF >= 9 ) {
        print "|-- [" $5 "] " $9
    }'

請注意,如果 awk 腳本必須包含'(單引號) 字符,則需要將其加引號:use '\''(閉單引號、文字單引號、開單引號)。

為了避免引用,您可以使用這裡的文檔反而。但這很尷尬,因為您不能使用標準輸入既向 awk 提供輸入又向腳本提供輸入。您需要使用額外的文件描述符(請參閱什麼時候會使用額外的文件描述符? 檔案描述符和 shell 腳本)。

#!/bin/bash
ls -lhF "$@" | awk -f /dev/fd/3 3<<'EOF'
( NF >= 9 ) {
    print "|-- [" $5 "] " $9
}
EOF

在 awk 中,您可以使用getline函數和管道構造從另一個命令讀取輸入。這不是 awk 的主要設計用途,但可以使其工作。您需要引用底層 shell 的檔案名稱參數,這很容易出錯。由於要處理的文字不是來自預期的來源(標準輸入或命令列上命名的檔案),因此您最終會得到區塊中的所有程式碼BEGIN

#!/usr/bin/awk -f
BEGIN {
    command = "ls -lhF"
    for (i = 1; i <= ARGC; i++) {
        arg = ARGV[i];
        gsub("'", "'\\''", arg);
        command = command " '" arg "'";
    }
    ARGC = 0; for (i in ARGV) delete ARGV[i];
    while ((command | getline) > 0) {
        if (NF >= 9) { print "|-- [" $5 "] " $9 }
    }
}

簡而言之,使用 shell 來做它擅長的事情(例如將命令連接在一起),使用 awk 做它擅長的事情(例如文字處理)。

答案2

我不太確定你想要做什麼,但可能出現的一個問題是awk列印ls被認為是最後一個欄位的內容,但awk不認為是這樣的(透過其預設解析)。例如。

-rw-r--r-- | 433k | filename-with-no-spaces      
-rw-r--r-- |   1k | link containing  spaces -> /home/user/filename-with-no-spaces

您需要以某種方式隔離最後一個ls欄位。下面採取的方法是尋找所有前面的欄位和分隔符號的長度。其餘的是文件名字段(加上其他信息,例如連結的目標)。 

下面的腳本確定可變寬度的最大寬度尺寸欄位(輸出格式所需)。有多種方法可以獲得這個寬度; 例如。(1)用於awk處理ls 輸出的每一行,在主循環中,將每一行加入數組以供後續END{ }處理。 或者(2) 將輸出寫入ls臨時文件,然後處理awk該文件。 下面所示的方法使用(2)

請注意, 的輸出ls可以按照您的方式發送一些可能是意外的、非簡單的輸出,就像 a 的情況一樣link,因此使用find和自訂它的輸出以更好地滿足您的解析需求通常更安全。

f=7               # the number of (multi-space) delimiters before the start of the filename  
myls="$(mktemp)"  # a temp file to hold  output from `ls`
w=$(ls --color=always -lFHk ~/ |tee "$myls" |awk '{print $5}' |wc -L) # max width of size field
h=k               # size unit
awk --re-interval -v"f=$f" -v"w=$w" -v"h=$h" '
  NF >= f {
    regex = "^([^ ]+ +){"f"}" 
    match( $0, regex )  # find start of name field
    printf( "%s | %"w"s%s | %s\n", $1, $5, h, substr( $0, RLENGTH ))
  }' "$myls"
rm "$myls"

答案3

我建議避免重新發明輪子,而是使用tree,它顯示目錄的文件/資料夾和子目錄文件/資料夾:

樹(1) - Linux 手冊頁

姓名

樹 - 以樹狀格式列出目錄內容。

概要

樹[-adfghilnopqrstuvxACDFNS] [-L 等級[-R]] [-H baseHREF] [-T 標題] [-o 檔名] [--nolinks] [-P 模式] [-I 模式] [--inodes] [ --device] [--noreport] [--dirsfirst] [--version] [--help] [--filelimit #] [目錄 ...]

描述

Tree 是一個遞歸目錄列表程序,可產生深度縮排的檔案列表。如果設定了 LS_COLORS 環境變量,輸出到 tty,並且使用了 -C 標誌,則支援顏色 ala dircolors。如果沒有參數,tree 會列出目前目錄中的檔案。當給予目錄參數時,樹依序列出在給定目錄中找到的所有檔案和/或目錄。完成列出找到的所有檔案/目錄後,樹將傳回列出的檔案和/或目錄的總數。

預設情況下,當遇到符號連結時,符號連結引用的路徑會印在連結名稱後面,格式如下:

名稱 -> 真實路徑

如果給出了“-l”選項並且符號連結引用實際目錄,則樹將遵循符號連結的路徑,就好像它是真實目錄一樣。

相關內容