![awk 腳本中的管道](https://rvso.com/image/23956/awk%20%E8%85%B3%E6%9C%AC%E4%B8%AD%E7%9A%84%E7%AE%A1%E9%81%93.png)
我正在嘗試編寫一個ls
包裝器,用於awk
解析ls -lhF
.現在我已將程式分成兩個檔案 -my_ls.sh
和my_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”選項並且符號連結引用實際目錄,則樹將遵循符號連結的路徑,就好像它是真實目錄一樣。