2010-12-06 35 views
2

我得到這個文本文件,調用stock.txt中,該文本文件的內容是:用bash命令處理數據文本文件?

pepsi;drinks;3 
fries;snacks;6 
apple;fruits;9 
baron;drinks;7 
orange;fruits;2 
chips;snacks;8 

我需要使用bash腳本拿出這樣的輸出:

Total amount for drinks: 10 
Total amount for snacks: 14 
Total amount for fruits: 11 
Total of everything: 35 

我的直覺告訴我,我需要使用sed,group,grep和其他東西。
我應該從哪裏開始?

+0

感謝您的誠實。是的,我們很容易得到直接的解決方案,但是如果我們只是爲你做,那麼你就會受到考試時間的影響。但這裏的人很樂意給你一些想法。 – 2010-12-06 17:32:05

+0

嗨拉夫,那是我擔心..考試..哈哈..因此,我需要誠實,並找到自己的解決方案,但我需要你的指導方針,我的課程筆記是非常有限的,缺乏例子。 – bashington02 2010-12-06 17:34:27

+1

您可以使用哪些工具有限制嗎? awk可以很容易地做到這一點...... – 2010-12-06 17:36:03

回答

0

我會向下突破練習幾個步

第1步:閱讀文件的一行在同一時間

while read -r line 
do 
    # do something with $line 
done 

步驟2:模式匹配(飲料,小吃,水果),並做一些簡單的算術。這一步需要你爲每一行標記出我將留下的練習,以供你弄清楚。

if [[ "$line" =~ "drinks" ]] 
then 
    echo "matched drinks" 
    . 
    . 
    . 
fi 
0

這裏有關於處理的簡短說明逗號在bash分隔的文件位置:

http://www.cyberciti.biz/faq/unix-linux-bash-read-comma-separated-cvsfile/

你可以做同樣的事情。只需將IFS從逗號更改爲分號即可。

哦是的,和學習bash的一般提示:man是你的朋友。使用此命令查看所有(或大多數)命令和實用程序的手冊頁。

例如:man read顯示讀命令的手冊頁。在大多數系統中,它將在less中打開,因此您應該按q退出手動(可能很有趣,但花了我一段時間才弄清楚)

1

Pure Bash。用於關聯數組一個很好的應用:

declare -A category     # associative array 
IFS=';' 
while read name cate price ; do 
    ((category[$cate]+=price)) 
done < stock.txt 

sum=0 
for cate in ${!category[@]}; do  # loop over the indices 
    printf "Total amount of %s: %d\n" $cate ${category[$cate]} 
    ((sum+=${category[$cate]})) 
done 

printf "Total amount of everything: %d\n" $sum 
0

的簡單的方法來做到這一點是利用哈希表,其通過bash的4.x和當然的直接支持可在AWK和Perl中找到。如果你沒有散列表,那麼你需要循環兩次:一次收集第二列的唯一值,一次總和。

有很多方法可以做到這一點。這裏有一個不使用awk,sed或perl的樂趣。我在這裏使用的唯一外部工具是剪切,排序和uniq。你甚至可以用更多的努力替換cut。事實上,第5-9行可能更容易用grep編寫,(grep $kind stock.txt),但我避免了炫耀bash的力量。

for kind in $(cut -d\; -f 2 stock.txt | sort | uniq) ; do 
    total=0 
    while read d ; do 
     total=$((total+d)) 
    done < <(
     while read line ; do 
      [[ $line =~ $kind ]] && echo $line 
     done < stock.txt | cut -d\; -f3 
    ) 

    echo "Total amount for $kind: $total" 
done 

我們在這裏失去了原始輸出的嚴格排序。你的練習可能是找到一種不這樣做的方法。

討論: 第一行描述了一個使用cut的簡單流水線的子shell。我們從stock.txt文件中讀取第三個字段,其中的字段描述爲;,在此處寫爲\;,因此shell不解釋它。結果是從stock.txt換行符分隔的值列表。這通過管道連接到sort,然後uniq。這將執行我們的「分組」步驟,因爲管道將輸出第二列中的項目的字母列表,但無論輸入文件中出現了多少次,它都只會列出一個項目。

同樣在第一行是典型的for循環:對於從子殼產生的每個項目,我們循環一次,將項目的值存儲在變量kind中。這是分組步驟的另一半,確保每個「總計」輸出行出現一次。

在第二行total被初始化爲零,因此無論何時啓動新組時,它都會重置。

第三行開始'totaling'循環,其中對於當前的kind,我們找到其出現的總和。在這裏我們聲明我們將在循環的每次迭代中從標準輸入讀取變量d

在第四行實際發生的總數:使用shell arithmatic我們將d中的值加到total中的值。

第五行結束while循環,然後描述其輸入。我們使用通過<的shell輸入重定向來指定循環的輸入,從而指定read命令來自文件。然後我們使用process substitution來指定該文件實際上是命令的結果。

在第六行上,將提供while-read循環的命令開始。它本身是另一個讀取循環,這次讀入變量line。在第七行上,測試通過conditional construct執行。這裏我們使用[[作爲=~運算符,它是一個模式匹配運算符。我們正在測試$line是否符合我們目前的$kind

在第八行我們結束內同時讀取循環,並指定其輸入來自stock.txt文件,那麼我們管的整個迴路的輸出,其通過現在是簡單地匹配$kind,以cut所有行和指示它僅顯示第三個字段,即數字字段。在第九行,我們結束進程替換命令,其輸出是由kind指定的組的行中的新行劃定的數字列表。

鑑於總數已知且種類已知,將結果打印到屏幕是一件簡單的事情。

0

下面的答案是OP的。由於它是在這個問題本身進行編輯的,並且OP還沒有回來6年,所以我正在編輯這個問題的答案,並將其作爲wiki發佈在這裏。


我的答案,得到的總價格,我用這個:

... 
PRICE=0 
IFS=";"  # new field separator, the end of line 
while read name cate price 
do 
let PRICE=PRICE+$price 
done < stock.txt 
echo $PRICE 

當我回聲,它的:35,這是正確的。現在我將繼續使用awk來獲取子類別結果。

整體解決方案:

謝謝你們,我設法自己做。這裏是我的代碼:

#!/bin/bash 
INPUT=stock.txt 
PRICE=0 
DRINKS=0 
SNACKS=0 
FRUITS=0 
old_IFS=$IFS  # save the field separator 
IFS=";"  # new field separator, the end of line 
while read name cate price 
do 
    if [ $cate = "drinks" ]; then 
     let DRINKS=DRINKS+$price 
fi 

if [ $cate = "snacks" ]; then 
     let SNACKS=SNACKS+$price 
fi 

if [ $cate = "fruits" ]; then 
     let FRUITS=FRUITS+$price 
fi 

# Total 
let PRICE=PRICE+$price 
done < $INPUT 

echo -e "Drinks: " $DRINKS 
echo -e "Snacks: " $SNACKS 
echo -e "Fruits: " $FRUITS 
echo -e "Price " $PRICE 
IFS=$old_IFS