我是 shell 腳本的新手。我想以表格格式分發檔案的所有資料并將輸出重定向到另一個檔案。
我有以下輸入檔案 File.txt
Fruit_label:1 Fruit_name:Apple
Color:Red
Type: S
No.of seeds:10
Color of seeds :brown
Fruit_label:2 fruit_name:Banana
Color:Yellow
Type:NS
我希望它看起來像這樣
Fruit_label| Fruit_name |color| Type |no.of seeds |Color of seeds
1 | apple | red | S | 10 | brown
2 | banana| yellow | NS
我想從文本檔案中逐行讀取所有資料,并制作像水果標簽、水果名稱、顏色、型別、種子數、種子顏色的標題,然后按行列印所有指定的值。以上所有資料都不同不同的水果,例如。香蕉沒有種子,所以想將其行值保留為空白..
有人能幫我一下嗎。
uj5u.com熱心網友回復:
這是我的解決方案。這是一份新年禮物,通常你必須展示你迄今為止嘗試過的東西,我們會幫助你,而不是為你做。
免責宣告一些大師可能會想出一個更簡單的 awk 版本,但這是有效的。
檔案 script.awk
# Remove space prefix
function ltrim(s) { sub(/^[ \t\r\n] /, "", s); return s }
# Remove space suffix
function rtrim(s) { sub(/[ \t\r\n] $/, "", s); return s }
# Remove both suffix and prefix spaces
function trim(s) { return rtrim(ltrim(s)); }
# Initialise or reset a fruit array
function array_init() {
for (i = 0; i <= 6; i) {
fruit[i] = ""
}
}
# Print the content of the fruit
function array_print() {
# To keep track if something was printed. Yes, print a carriage return.
# To avoid printing a carriage return on an empty array.
printedsomething = 0
for (i = 0; i <= 6; = i) {
# Do no print if the content is empty
if (fruit[i] != "") {
printedsomething = 1
if (i == 1) {
# The first field must be further split, to remove "Fruit_name"
# Split on the space
split(fruit[i], temparr, / /)
printf "%s", trim(temparr[1])
}
else {
printf " | %s", trim(fruit[i])
}
}
}
if ( printedsomething == 1 ) {
print ""
}
}
BEGIN {
FS = ":"
print "Fruit_label| Fruit_name |color| Type |no.of seeds |Color of seeds"
array_init()
}
/Fruit_label/ {
array_print()
array_init()
fruit[1] = $2
fruit[2] = $3
}
/Color:/ {
fruit[3] = $2
}
/Type/ {
fruit[4] = $2
}
/No.of seeds/ {
fruit[5] = $2
}
/Color of seeds/ {
fruit[6] = $2
}
END { array_print() }
- 要執行,請呼叫
awk -f script.awk File.txt awk每行處理一個檔案行。所以這個想法是將水果資訊存盤到一個陣列中。- 每次找到“Fruit_label:.....”這一行時,列印當前的水果并開始一個新的。
- 由于每行都是按順序讀取的,因此您
awk可以根據模式告訴如何處理每一行。 - 模式是包含在
//每個代碼段開頭的字符之間的內容。 - 難點:由于第一行包含每個水果的 2 個資訊,并且我在
:字符上剪切了行,因此 Fruit_label 將包含“Fruit_name”。 - 即:第一行是這樣剪的:
$1 = Fruit_label,$2 = 1 Fruit_name,$3 = Apple - 這就是
array_print()函式如此復雜的原因。 - 修剪函式用于洗掉空格。
- 就像蘋果一樣,
Type: S當分裂時:會導致S
如果它符合您的要求,請參閱https://stackoverflow.com/help/someone-answers以接受它。
uj5u.com熱心網友回復:
另一種方法是“裝飾和處理”方法。什么是“裝飾與加工”?為了裝飾是把你的文字,并與另一分離器裝飾它使現場更容易分裂-像你的情況你的欄位可以包含與一起包括空格':'場名稱和值之間的分隔符。周圍有不一致的空白':'- 這使得處理成為一場噩夢......很簡單。
因此,與其擔心分隔符是什么,不如想想“欄位應該是什么?” 然后添加一個新的分離器(裝飾的欄位,然后之間)工藝用awk。
這里sed是用來裝點你的輸入'|'作為分隔符(第二個電話消除了'|'最后一個欄位后),然后一個簡單的awk程序被用于split()該領域上':'獲得欄位名和欄位值,其中域值被簡單地印刷并且欄位名存盤在一個陣列中。當發現重復的欄位名時——它被用作seen變數來指定記錄之間的變化,例如
sed -E 's/([^:] :[[:blank:]]*[^[:blank:]] )[[:blank:]]*/\1|/g' file |
sed 's/|$//' |
awk '
BEGIN { FS = "|" }
{
for (i=1; i<=NF; i ) {
if (split ($i, parts, /[[:blank:]]*:[[:blank:]]*/)) {
if (! n || parts[1] in fldnames) {
printf "%s %s", n ? "\n" : "", parts[2]
delete fldnames
n = 1
}
else
printf " | %s", parts[2]
fldnames[parts[1]]
}
}
}
END { print "" }
'
示例輸出
有了您的輸入,file您將擁有:
1 | Apple | Red | S | 10 | brown
2 | Banana | Yellow | NS
您還將看到一個“裝飾-排序-取消裝飾”,用于通過使用新的最后一個欄位“裝飾”您的資料,對該欄位進行排序,然后“取消裝飾”以洗掉新的不存在的值列上的資料排序完成時的附加欄位。這允許按資料排序,這些資料可能是任何兩列的總和(或組合)等......
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/400973.html
上一篇:處理bash腳本中的特殊字符
