2016-07-30 72 views
-1

我的問題是不容易問,我試着用下面的例子說明問題:計數grep的結果在bash腳本不會工作

/home/luther/tipical_surnames.txt

Smith 
Johnson 
Williams 
Jones 
Brown 
#Davis 
Miller 
Wilson 
#Moore 
Taylor 
Anderson 

/家/luther/employers.txt

2000 Johnson  A lot-of details/BJC3000,6000, i550    0 
2101 Smith  A lot-of details/BJC3000,6000, i550    0 
2102 Smith  A lot-of details/BJC3000,6000, i550    0 
2103 Jones  A lot-of details/BJC3000,6000, i550    0 
2104 Johnson  A lot-of details/BJC3000,6000, i550    0 
2100 Smith  A lot-of details/BJC3000,6000, i550    0 

我有一個最喜歡的姓氏列表和另一個僱主的名字。 讓我們來看看有多少人在該公司擁有最流行的姓,使用控制檯:

grep -v "#" /home/luther/tipical_surnames.txt | sed -n 1'p' | cut -f 1 
Smith 
grep Smith /home/luther/employers.txt | wc -l 
230 

工作完美。 現在讓我們用一個簡單的bash腳本檢查前5個最受歡迎的姓氏:

#!/bin/bash 
counter=1 
while [ $counter -le 5 ] 
do 
    surname=`grep -v "#" /home/luther/tipical_surnames.txt | sed -n "$counter"'p' | cut -f 1` 
    qty=`grep "$surname" /home/luther/employers.txt | wc -l` 
    echo $surname 
    echo $qty 
    counter=$(($counter + 1)) 
done 

而且結果如下:

Smith 
0 
Johnson 
0 
Williams 
0 
Jones 
0 
Brown 
0 

的哪些錯誤?

更新: 就像我寫的,我測試了其他電腦上的腳本,一切工作正常。 後,我嘗試如下:

[email protected]:/var/www# cat testfile.bash 
#!/bin/bash 
for ((c=1; c<=5; c++)) 
{ 
echo $c 
} 

[email protected]:/var/www# bash testfile.bash 
testfile.bash: line 2: syntax error near unexpected token `$'\r'' 
'estfile.bash: line 2: `for ((c=1; c<=5; c++)) 
[email protected]:/var/www# echo $BASH_VERSION 
4.2.37(1)-release 
[email protected]:/var/www# 

當然,其他計算機上如預期這只是劇本的工作,沒有錯誤。

+0

shell是調用工具的環境,而不是操縱文本的工具。用於處理文本的標準通用UNIX工具是awk。由於您使用了錯誤的工具,因此您正在努力工作,並且在shell中執行您想要的功能會非常複雜且效率低下(請參閱[爲什麼要使用shell循環處理文本]認爲壞實踐(http://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice))。把它扔掉,用awk重新開始。發佈簡潔,可測試的樣本輸入和預期輸出,我們可以爲您提供幫助。 –

+0

我猜你是有DOS行結束符的文件。複製/粘貼程序輸出時,你不會看到它們,但它們會出現在捕獲的變量中,並阻止最終的'grep'匹配任何東西。在文件上嘗試'dos2unix'。爲了進一步排除故障,[Stack Overflow'bash' tag wiki](// stackoverflow.com/tags/bash/info)有關於這個問題的詳細部分。 – tripleee

+0

@Ed Morton好吧,它很清楚,但我仍然不明白爲什麼我的代碼會很好,如果我將$ surname變量替換爲值。正如你從結果中看到的,當我想把它打印到屏幕上時,$ surname變量具有很好的價值。爲什麼當我使用聲明$ qty變量時,同一個變量不會工作? – Luther

回答

0

我其實不太確定。我測試了你的腳本,通過複製並粘貼它,用想象中的數據(/usr/share/dict/words),它似乎按預期工作。我想知道您發佈的腳本與您正在運行的腳本之間是否有區別?

雖然在此,我冒昧地讓它運行得更順暢。請注意,在循環中,您是如何在每次迭代中讀取整個姓氏文件的?另外,grep + wc -l可能被grep -c替代。由於模式(#)是固定字符串,因此我還在第一次調用grep時添加了-F。員工檔案中的grep使用\<$name\>以確保我們只在$nameJohn時纔得到Johns和Johnssons。

#!/bin/bash 

employees_in="/usr/share/dict/words" 
names_in="/usr/share/dict/words" 

grep -v -F "#" "$names_in" | head -n 5 | cut -f 1 | 
while read -r name; do 
    count="$(grep -c "\<$names\> " "$employees_in")" 
    printf "name: %-10s\tcount: %d\n" "$name" "$count" 
done 

測試它:

$ bash script.sh 
name: A    count: 1 
name: a    count: 1 
name: aa   count: 1 
name: aal   count: 1 
name: aalii   count: 1 

注:我只獲取計數的人,因爲字典(這並不奇怪)只包含獨特的單詞。

+0

感謝您的回覆和解決方案。粘貼代碼沒有區別。我嘗試了與其他計算機和生成的源文件,它的工作正常。這個問題可能與源文件有關。 – Luther

+0

@路德是的,如果員工文件是空的或者根本不包含從姓氏文件中讀取的名字(這將很容易檢查)。我的印象是,儘管你在同一臺計算機上運行了第一個命令行示例和腳本。 – Kusalananda

+0

當約翰遜與約翰斯頓,史密斯到史密瑟斯等匹配時,以及當它與名爲約翰斯頓的員工與公司名稱約翰斯頓和約翰斯頓等匹配時,這會失敗。 –

2

這顯然是未經檢驗的,因爲你還沒有發佈樣本輸入,但是這是一種方法,你應該使用:

awk ' 
NR==FNR { if (!/#/) cnt[$1]=0; next } 
{ cnt[$WHATEVER]++ } 
END { 
    PROCINFO["sorted_in"] = "@val_num_desc" 
    for (name in cnt) { 
     print name, cnt 
     if (++c == 5) { 
      break 
     } 
    } 
} 
' /home/luther/tipical_surnames.txt /home/luther/employers.txt 

替換「什麼」與在僱員的姓都存儲在僱主的場數。文本。

以上使用GNU AWK爲sorted_in,與其他awks我只是從出環和管道輸出的PROCINFO線和數進行排序,然後頭,如:

awk ' 
NR==FNR { if (!/#/) cnt[$1]=0; next } 
{ cnt[$WHATEVER]++ } 
END { 
    for (name in cnt) { 
     print name, cnt 
    } 
} 
' /home/luther/tipical_surnames.txt /home/luther/employers.txt | sort -k2,1nr | head -5 

或什麼正確的排序選項是。

+0

感謝您的解決方案,它的外觀非常有用!但我仍然不知道爲什麼我的代碼不會工作。 – Luther

+0

同樣,用於處理文本的shell腳本很脆弱,難以正確寫入。有很多事情可能導致這個問題,很難猜測哪一個實際上在做這件事。我看到你在'surname = ...'行末尾使用'cut -f 1' - 這絕對不會做任何事情用你發佈的文件格式 - 你認爲它會做什麼?您發佈的文件只有1個字段,那麼爲什麼你顯然試圖選擇1字段,當這是文件中的全部內容? –