[英]Basic Linux Bash Scripting while / for
在 bash 腳本中做我的第一步。 到目前為止,我已經完成了 5/7 的練習,卡在了最后兩個練習中,我找不到解決它的方法。
這是請求的練習的更好翻譯,同樣應該使用簡單的命令來解決,如 sed、echo、cat、uniq、tr、grep、wc 等:
編寫顯示默認 shell 是您機器上可用 shell 之一的用戶數量的命令行。 執行命令時,對於每個 shell,我們將得到與以下相同形式的結果:
- 0 個用戶擁有 shell / bin / sh
- 11 個用戶有 for shell/bin/bash
- 0 個用戶有 for shell /usr/bin/sh
- 0 個用戶有 for shell /usr/bin/bash
@托德
我今天早上做到了,你的 grep 重定向輸入給了我這個想法。 我是這樣做的:
result=$(grep -of <(echo $SHELL) /etc/passwd | uniq -c)
count=$(echo $result I awk -F” “ '{print $1}')
shell=$(echo $result | awk -F” “'{print $2}')
echo $result | while read i; do
echo $count utilisateurs ont pour shell $shell
done
在 Bash 中,有很多方法可以做到這一點。 但是,從實際的角度來看,您實際上並不需要 Bash 本身來解決這個問題。 標准的 *nix 工具可以正常工作,前提是您正確鏈接它們。 例如,如果輸出的特定格式不是重點:
$ grep -of <(grep '^/.*$' /etc/shells) /etc/passwd | sort | uniq -c
11 /bin/bash
8 /bin/sh
4 /usr/local/bin/fish
這基本上是從 /etc/shells 中 grep 你的 shell,然后 grep將該輸出視為一個文件來讀取表達式以匹配 /etc/passwd。 然后它將結果通過管道傳送到 sort 和 uniq 實用程序以計算出現次數。 它依賴於進程替換,並非所有 shell 都具有或以相同的方式表達,但是您的問題被標記為 Bash,因此避免 Bashisms 不是主要問題。
但是,由於並非所有 shell 都具有 Bash 所做的進程替換重定向,因此此類解決方案在不同 shell 之間並不是 100% 可移植的。 通常有一種類似的方法可以做到這一點,但有時跨系統和 shell 的可移植性確實很重要。 無論如何,這顯示了 grep、管道和進程替換的強大功能。
獲得原始數據后,您可以使用 printf、awk 甚至 sed 對輸出進行格式化(如果您希望它采用不同的格式)。 但是,如果重點是計算 shell 使用情況,那么在 Bash 或 zsh 中這是一種簡單的方法。
更復雜(但也更便攜)的替代方法是使用 xargs 作為管道的核心元素。 例如:
$ grep -o '^/.*$' /etc/shells |
xargs -I{} -L1 -- sh -c 'echo "{}"; grep -Fc "{}" /etc/passwd' |
xargs -n2
/bin/bash 11
/bin/csh 0
/bin/ksh 0
/bin/sh 8
/bin/tcsh 0
/bin/zsh 0
/usr/local/bin/fish 4
這將找到 /etc/shells 中的所有 shell,一次一個地將它們傳遞給 Bourne 腳本以打印 shell 的路徑,並讓 grep 的固定字符串匹配器計算 /etc/passwd 中的出現次數,然后將輸出通過管道傳輸到 xargs再次加入線路,一次備份兩條。
這種方法的主要好處是它會列出所有shell,無論是否有人使用它們。 您甚至可以將最后一行更改為tac | xargs -n2
tac | xargs -n2
如果您希望在外殼名稱之前列出數字。
這就是我如何理解您的問題,一種使用數組的方法,包括關聯數組。
#!/usr/bin/env bash
declare -A Shell_and_Users
while IFS=: read -ra lines; do
login_shell="${lines[-1]}"
((Shell_and_Users["$login_shell"]++))
done < /etc/passwd
要檢查關聯數組Shell_and_Users
的值, Shell_and_Users
運行:
declare -p Shell_and_Users
現在循環遍歷關聯數組以打印所需的輸出。
for i in "${!Shell_and_Users[@]}"; do
printf -- '- %d users have shell %s\n' "${Shell_and_Users[$i]}" "$i"
done
如果不是這種情況,那么編輯問題並添加更多詳細信息,如果文件/etc/shells
應該是 parse/involve,因為上面的解決方案永遠不會打印0 users
。
你走在正確的軌道上。 您可以使用以下腳本:
#!/bin/bash
# usual syntax to read a file line by line
# https://linuxhint.com/while_read_line_bash/
while IFS= read -r shell
do
# if our file contains commented lines, we ignore them
[[ "$shell" =~ ^[[:space:]]*# ]] && continue
count=$(grep -c ".*:$shell" /etc/passwd)
echo "- $count users have shell $shell"
done < /etc/shells
這里, /etc/shells
是一個包含系統上所有可用登錄 shell 的文件。 /etc/passwd
是另一個系統文件,包含系統上每個用戶的列表,以及與之關聯的 shell(格式: <username>:XXX:XXX:XXX:XXX:XXX:<shell>
)
我們使用grep -c ".*:$shell" /etc/passwd
來查找/etc/passwd
中以:<the current shell>
結尾的行數
編輯:如果教授為您提供了一個 shell 列表,您可以將它們全部粘貼到一個文件中(即input.txt
)並將done < /etc/shells
替換為done < ./input.txt
假設可以使用awk
,你可以試試這個
$ cat awk.script
#!/usr/bin/env awk -f
BEGIN {
FS=":"
} $NF=="/bin/bash" {
count_bash++
bash=$NF
} $NF=="/usr/bin/bash" {
count_bash2++
bash2=$NF
} $NF=="/bin/sh" {
count_sh++
sh=$NF
} $NF=="/usr/bin/sh" {
count_sh2++
sh2=$NF
} END {
print count_bash " users have a shell for "bash "\n" \
count_bash2" users have a shell for "bash2 "\n" \
count_sh " users have a shell for "sh "\n" \
count_sh2" users have a shell for "sh2 "\n" \
}
這將提供與您預期的輸出類似的輸出,但是,如果未使用 shell,您將獲得一個空輸出,其中沒有值或路徑,這可能並不理想。
輸出
$ awk -f awk.script /etc/passwd
24 users have a shell for /bin/bash
users have a shell for
2 users have a shell for /bin/sh
users have a shell for
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.