2016-09-15 34 views
1

我需要做的是從etc/group獲取用戶列表,然後對其進行排序,然後對唯一條目進行計數。對字符串數組中的唯一條目進行排序和計數

現在我只設法獲取用戶名。但我懷疑這是錯誤的。

#!/bin/bash 
usernames=(); 

while IFS=: read -r Groups Tmp1 Tmp2 Username 
do 
    if [ $Username!="" ]; 
    then 
    usernames+=($Username); 
    fi; 
done < /etc/group 

然後,我還試圖對它進行排序,但輸出非常怪異:

排序:

IFS=$'\n' sorted=($(sort <<<"${usernames[*]}")) 
unset IFS 

輸出:

echo ${usernames[@]} 
echo "" 
echo ${sorted[@]} 

結果:

root root root root root root _teamsserver root root _taskgated root root,_jabber,_postfix,_cyrus,_calendar,_dovecot _calendar,_jabber,_postfix _devicemgr,_teamsserver _eppc root _teamsserver _devicemgr _softwareupdate _locationd _teamsserver _devicemgr,_calendar,_teamsserver,_xserverdocs _teamsserver,_devicemgr _warmd 

_calendar,_jabber,_postfix _devicemgr _devicemgr,_calendar,_teamsserver,_xserverdocs _devicemgr,_teamsserver _eppc _locationd _softwareupdate _taskgated _teamsserver _teamsserver _teamsserver _teamsserver,_devicemgr _warmd root root root root root root root root root root root,_jabber,_postfix,_cyrus,_calendar,_dovecot 

我有零bash的經驗,絕對不能得到它的工作。

我需要什麼最基本的解決方案來獲取來自/ etc/group的用戶名的排序列表,只有唯一的條目和打印每個的重複數量。

對於離,如果我有這個/etc/group文件:

nobody:*:-2: 
nogroup:*:-1: 
wheel:*:0:root 
daemon:*:1:root 
kmem:*:2:root 
sys:*:3:root 
tty:*:4:root 
operator:*:5:root 
mail:*:6:_teamsserver 

我想這一點:

root 6 
_teamsserver 1 
+0

請添加一個可驗證的樣本我/ p和預期o/p。你的'/ etc/group'文件和你的輸出格式。 – Inian

+0

嘗試'cut -d:-f1/etc/group |排序| uniq -c' – Sundeep

+0

剛剛添加了所需的示例 – s1ddok

回答

3

每一個「用戶名」字段實際上是用戶名的任意空逗號分隔的列表。爲了分隔用戶名,你需要用逗號分隔條目。

如果我從你的循環開始了,我可能會使用:

sorted=($(while IFS=: read -r Groups Tmp1 Tmp2 Usernames 
      do 
       if [ -n "$Usernames" ]; 
       then 
        echo "$Usernames" 
       fi 
      done < /etc/group | 
      tr ',' '\n' | 
      sort -u 
     )) 

echo "${sorted[@]}" 

這繞過了中間usernames陣列。如果你真的想要的,然後讓你的原始循環和管道sort之前通過tr命令輸入sort

IFS=$'\n' sorted=($(tr ',' '\n' <<<"${usernames[*]}" | sort -u)) 

這會生成一個數組,sorted,包含排序順序的唯一名稱的列表。但是,如果你想要的是唯一名稱的計數,那麼我可能會在awk中做所有事情。事實上,我很想用awk而不是while循環。

如果要計算每個唯一名稱的出現次數,則使用sort | uniq -c而不是sort -u。統計上的選項和變體是軍團 - 關鍵點是你需要將逗號分割爲/etc/group文件的最後一個字段。如果您出於某種原因在列表中有空格,則可能也必須刪除這些空格。 tr ', ' '\n'會這樣做。

使用awk,你可以這樣做:

awk -F: '{ n = split($4, a, ","); for (u = 1; u <= n; u++) count[a[u]]++i } 
     END { for (u in count) print u, count[u] }' /etc/group 

它拆分第四場入陣a,然後計算每個名字的出現的count陣列英寸最後,它打印count陣列的條目。在我的Mac上,它取得了以下效果:

root 11 
_warmd 1 
_locationd 1 
_jabber 2 
_taskgated 1 
_postfix 2 
_devicemgr 4 
_calendar 3 
_cyrus 1 
_teamsserver 6 
_dovecot 1 
_xserverdocs 1 
_eppc 1 
_softwareupdate 1 

您可以根據需要進行進一步排序。

+0

我試圖運行你的代碼,但得到這個錯誤:'語法錯誤附近意外的令牌「;」如果[-n「$用戶名」];' – s1ddok

+0

有一個(重大)錯誤 - 這是當你不檢查時會發生什麼。我已經用測試過的代碼更新了shell代碼(在數組賦值的內容中添加了'$(...)',您仍然需要調整命令以獲得所需的結果(例如,使用'sort | uniq -c ''以獲得每個名稱的計數) –

+0

好吧!看起來正是我需要的東西 – s1ddok

2

你可以嘗試這樣的事情:

awk -F ':' '{ if(length($4)) { gsub(",", "\n", $4); print $4 } }' /etc/group | \ 
    sort | uniq -c 

awk命令將所有非空第四字段(':'作爲分隔符),並與取代''「\ n '萬一一組有多個用戶。

然後,我們對獨特的外觀進行排序和計數。

編輯:

沒有awk

cut -d: -f4 /etc/group | tr ',' '\n' | grep -v '^$' | sort | uniq -c 
+0

如果將第四個字段拆分爲一個數組,然後使用該數組生成awk中每個用戶名的計數,然後你會在最後打印。 –

+0

對不起,我不能使用AWK,我需要純粹的bash解決方案 – s1ddok

+0

對不起,我不清楚問題的要求,upvoted for awk – s1ddok

0

稍加修改示例輸入到包括,分隔的名字

$ cat abc.txt 
nobody:*:-2: 
nogroup:*:-1: 
wheel:*:0:root 
daemon:*:1:root 
kmem:*:2:root,test 
sys:*:3:root 
tty:*:4:root,t1,test 
operator:*:5:root 
mail:*:6:_teamsserver 

$ perl -F: -le 'foreach (split /,/,$F[3]){$h{$_}++ if /./} END{foreach (keys %h){print "$_ $h{$_}"}}' abc.txt 
t1 1 
_teamsserver 1 
root 6 
test 2 
  • -F:分割輸入線上:並保存到@F陣列
  • foreach (split /,/,$F[3])迭代在第四場分上,
  • $h{$_}++ if /./增量散列如果非空
  • END{foreach (keys %h){print "$_ $h{$_}"}}打印所需格式的哈希信息
+0

對不起,我不能使用perl。我需要純粹的bash解決方案 – s1ddok

+1

@ s1ddok:「純粹的bash」是什麼意思? Perl是一個命令; Awk是一個命令; 'tr'是一個命令; 'sort'是一個命令; 'uniq'是一個命令:沒有一個是'純Bash',因爲Bash運行另一個命令。 –

+0

@JonathanLeffler我可能聽起來像一個新手,因爲我從來沒有經歷過bash編程,我想說的是我不能使用除默認命令以外的任何其他腳本語言 – s1ddok

1
cut -d: -f4 /etc/group | tr , '\n' | grep '.' | \ 
sort | uniq -c | join -a 1 -o '1.2,1.1' - /dev/null 

或者:

cut -d: -f4 /etc/group | tr , '\n' | grep '.' | \ 
sort | uniq -c | awk '{ print $2 " " $1 }' 

工作原理:

  1. cut了實地#4
  2. tr將逗號更改爲換行符。
  3. grep刪除空白行。
  4. sort,count uniq ue lines,print using OP's spec。
+1

爲什麼「rev」?你可以簡單地使用'cut -d:-f4'而不需要'rev'。 –

+0

我不認爲我理解這是如何工作,但upvoted – s1ddok

+0

@JonathanLeffler,你是對的,謝謝。 (對/ etc/group有一種模糊的理解,我沒有想到域的數量,只是需要* last *)。 – agc

相關問題