シェルスクリプトでarrUsersという配列を宣言しました。最後のコマンドを使用して、すべてのユーザーがLinuxサーバーにログインできるようにします。私はこのようなことをしたい:
declare -a arrUsers=()
for user in `last | awk '{print $1}'
do
if $user not in arrUsers()
do arrUsers += users
これを行うのに正しい構文が何であるかよくわかりません。どんな助けでも大変感謝します。
答え1
ここでは2つの異なる点を見ることができます。正常にログインしたユーザーのリストを取得し(1)、そのリストをBash配列に追加する(2)。
解析された出力には、
last
ユーザー名で始まらない行も含まれるため、単純ではありません。 Linuxにはいくつかの選択肢があります。lslogins -r | awk -F '[ ]' 'NR > 1 && $6 { print $2 }'
lslogins
ユーザーに関する情報(ログインイベントではない)を表示するため、ユーザーごとに1行だけ出力されます。この-r
オプションは、出力を列で区切らないように指示することで、単一のスペースを列の区切り文字と見なし、単一のスペースでない場合にスペース文字が圧縮されるのをawk
防ぐ機能(デフォルト)を利用できるようにします。ただし、出力フィールドの内容に空白文字が表示されるかどうかはFS
わかりません。lslogins
または:
utmpdump /var/log/wtmp 2>/dev/null | gawk -v FPAT='\\[[^][]*\\]' ' $1 == "[7]" { gsub(/[][]/,"",$4); sub(/ +$/,"",$4); users[$4] } END { for (user in users) print user }'
これは、非標準のGNU AWK機能を使用して、フィールドの
FPAT
内容を記述する正規表現(に格納されている)に基づいてレコードを分割します。出力では、utmpdump
フィールドは角かっこで囲まれ、スペースで区切られます。最初のフィールドに保存されているタイプに基づいてレコードをフィルタリングします(man 5 wtmp
詳細については、参考資料を参照)。そのような名前を作成することは確かに賢明な選択ではありませんが、Linuxでは以下に従わないユーザー名を受け入れます。基準にない文字が含まれています。移植可能なファイル名文字セット--スペースを含みます。空白文字は問題ありません
lslogins -r
。空白文字はエスケープされますが、たとえば、末尾の空白は出力に明示的に表示されず、\x20
上記のスニペットから空白文字を削除します。utmpdump
以下を使用して、一意のユーザー名のリストを配列に配置できます。
readarray -t users \ < <(lslogins -r | awk -F '[ ]' 'NR > 1 && $6 { print $2 }')
または、リセットせずに既存の配列に要素を追加します。
readarray -t -O "${#users[@]}" users \ < <(lslogins -r | awk -F '[ ]' 'NR > 1 && $6 { print $2 }')
しかし、これは要素の一意性を保証するものではありません。これを達成するには、複数のループが必要な場合があります。
while IFS= read -r user do for el in "${users[@]}" do if [ "$el" = "$user" ] then continue 2 fi done users+=( "$user" ) done < <(lslogins -r | awk -F '[ ]' 'NR > 1 && $6 { print $2 }')
代わりに(Bashバージョンがサポートしている場合)、連想配列を使用してユーザー名をキーとして保存して、各ユーザー名が一度だけ表示されるようにすることもできます。
declare -A users while IFS= read -r user do users["$user"]='' done < <(lslogins -r | awk -F '[ ]' 'NR > 1 && $6 { print $2 }')
その後、次の構文を使用して繰り返すことができます
"${!array[@]}"
。for username in "${!users[@]}" do printf '%s\n' "$username" done