질문이 있습니다:
운동은 다음과 같습니다
지난 15일 동안 로그인하지 않았으며 "alumnos" 그룹에 속한 사용자를 검색하는 스크립트를 작성하세요. 목록은 /var/log/alumnos_sin_login에 추가됩니다.
내 접근 방식:
#2)
#!/bin/bash
#Scripts which detects users whose group is "alumnos" who have been not logged in,
#in the last 15 days. The users' list is added to /var/log/alumnos_sin_login
#RESULTADO holds those users who haven't entered in the last 15 days
#LISTA holds alumnos' users' list
#USUAEIO actual user being parsed
#RAIZ != "" if user has logged -15 days
#Read and check if group is not created
exec 0 </etc/gshadow
if [ $(grep "alumnos:") -e ]
then
echo "Grupo alumnos no existe"
exit 1
fi
RESULTADO="Los alumnos que llevan más de 15 días sin loguearse son: "
LISTA=$(grep "alumnos:" | cut -d ':' -f 4)
IFS=,
for USUARIO in $LISTA
do
RAIZ=$(find /home/$USUARIO -atime +15 | grep "/home/$USUARIO")
if [ $RAIZ != "" ]
then
RESULTADO="$RESULTADO $USUARIO"
fi
done
echo $RESULTADO >> /var/log/alumnos_sin_login
exit 0
질문: 이 문장을 어떻게 개선할 수 있나요?
if [ $(grep "alumnos:") -e ]
그룹이 생성되었는지 확인하세요. 존재하지 않으면 제대로 작동하지만 존재하는 경우 다음과 같이 보고합니다.
bash: [: ==: unary operator was expected
왜?
둘째, 사용자가 지난 15일 동안 로그인하지 않았는지 알 수 있는 더 좋은 방법이 있습니까? 코드에서는 해당 디렉토리가 /home/name_of_user이고 표준이 아니라고 가정하기 때문입니다. 내 말은, 마지막 사용자의 로그인 시간을 가져오는 명령이 있는지, 아니면 적어도 그들의 디렉토리를 제대로 알 수 있는 방법이 있는지, 모르기 때문입니다.
당신의 도움을 주셔서 감사합니다.
답변1
지난 15일 동안 로그인하지 않은 사용자 목록을 얻는 가장 쉬운 방법은 /home
다음 lastlog
명령을 사용하는 것입니다.
lastlog -b 15
출력 줄을 봅니다.
alumno1 pts/14 172.17.1.114 2016년 10월 22일 토요일 22:18:57 +0100
이름(첫 번째 필드)만 원하는 경우:
lastlog -b 15 | sed "1d" | awk ' { print $1 } '
( 헤더를 sed "1d"
제거하는 데 사용되는 경우 lastlog
)
~에서남자의 마지막 기록:
옵션 lastlog 명령에 사용 가능한 옵션은 다음과 같습니다.
-b, --before DAYS Print only lastlog records older than DAYS.
사용자가 로그인한 적이 없는 경우 포트 및 시간 대신 "로그인되지 않음" 메시지가 표시됩니다.
그룹을 확인하는 실제 스크립트는 다음과 같습니다.
#!/bin/bash
getent group alumnos > /dev/null
if [ $? -ne 0 ]
then
echo "group alumnos does not exist"
exit 1
fi
for i in ` lastlog -b 15 | sed "1d" | awk ' { print $1 } '`
do
if [ `id -ng $i` == "alumnos" ]
then
echo $i
fi
done
exit 0
여기서:
변수는 현재 반복 "$i"가 가리키는 사용자 그룹의 이름이 주어지면 i
주어진 모든 사용자의 이름을 반복하여 그룹이 존재하는지 확인합니다.lastlog
id -ng user
getent group alumnos
if
언급한 오류는 아무것도 발견되지 않으면 피연산자 grep
가 누락되어 비어 있게 됩니다. 트릭 중 하나는 다음과 같이 문자열 비교를 "x"로 채우는 것입니다.
if [ "x"$i == "xstring" ]
then
...
그룹 동문이 있는지 확인하는 또 다른 옵션:
if [ $(grep "^alumnos:" /etc/group) -e ]
then
echo "No group alumnos"
exit 1
fi
여러 그룹의 사용자를 확인하는 또 다른 옵션:
groups user | grep alumnos
답변2
보충 그룹에 속한 사용자를 나열하려면 foo
다음을 사용하십시오.
getent group foo | cut -d ':' -f 4- | tr -s '\n,' '\n\n'
이것getent
이 명령은 "이름 서비스 스위치"를 사용합니다. 이는 사용자 정보와 비밀번호가 원격 서버에 저장되어 있는 시스템에서도 getent
사용자 정보를 계속 얻을 수 있음을 의미합니다.
getent passwd
파싱하는 대신/etc/passwd
getent group
파싱하는 대신/etc/group
위에서 세 번째 인수를 지정하면 해당 항목만 표시됩니다. ( shadow
및 gshadow
도 있지만 getent
특별한 권한이 있는 사용자에게만 정보를 제공합니다.)
출력은 getent group foo
다음과 유사합니다.
foo:x:1001:user1,user2,user3
여기서 첫 번째 필드는 그룹 이름, 두 번째 필드는 그룹 비밀번호( *
비밀번호가 없거나 x
파일에만 있는 경우 gshadow
), 세 번째 필드는 그룹 ID 번호, 네 번째 필드는 쉼표로 구분된 목록입니다. 사용자는 이 그룹을 보조 그룹으로 설정할 수 있습니다.
이 cut -d ':' -f 4-
명령은 각 줄에서 콜론으로 구분된 처음 3개의 필드를 제거합니다. (즉, 각 입력 줄에서 네 번째 이후의 콜론으로 구분된 필드만 출력합니다.) 이렇게 하면 그룹 이름, 비밀번호 참조 및 그룹 ID 번호가 제거됩니다.
모든 쉼표를 줄 바꿈으로 변환 tr -s '\n,' '\n\n'
하고 모든 연속 줄 바꿈(및 쉼표)을 단일 줄 바꿈으로 결합합니다.
foo
따라서 출력은 보조 그룹으로서의 사용자 이름이며 한 줄에 하나의 사용자 이름입니다.
id -gn
이 목록에는 기본 그룹( )이 ; 인 사용자는 포함되지 않습니다 foo
. foo
( )를 보충군으로 한 것 id -Gn
.
foo
기본 그룹의 사용자를 나열하려면 다음을 사용하십시오.
getent passwd | awk -F ':' '$4=='$(id -g foo)' { print $1 }'
이번에는 전체 passwd 데이터베이스를 덤프하고 awk
.
이 $(id -g foo)
부분은 실제로 작은따옴표 외부에 있으므로 group 의 그룹 ID 번호로 확장됩니다 foo
. awk 규칙은 각 줄의 콜론으로 구분된 네 번째 필드를 foo
( group 의) 그룹 ID 번호와 비교하고, 일치하면 첫 번째 필드(사용자 이름)를 인쇄합니다.
이것lastlog
이 명령을 사용하여 사용자의 로그인 기록을 얻을 수 있습니다. 이 -t
옵션을 사용하면 레코드가 고려되는 일수를 지정할 수 있습니다.
명령 출력(특히 날짜 형식)이 lastlog
현지화되었습니다. 이는 사용자 로케일이 출력에 날짜가 표시되는 방식에 영향을 미친다는 것을 의미합니다 lastlog
. 출력이 항상 영어이고 영어 날짜 형식을 사용하도록 하려면 다음을 사용하십시오.
LANG=C LC_ALL=C lastlog
이는 LANG=C LC_ALL=C
로케일 설정을 지정하는 데 가장 일반적으로 사용되는 두 가지 환경 변수입니다. 셸을 사용하면 개별 명령의 환경을 명령 자체 앞에 배치하여 일시적으로 재정의할 수 있습니다.
예를 들어 지난 10일 동안 로그인하지 않은 사용자만 나열하려면 다음을 사용하면 됩니다.
LANG=C LC_ALL=C lastlog -t 10 | awk '/Never logged in/ { print $1 }'
그러나 이것이 foo
해당 그룹의 구성원으로 선택을 제한하는 것은 아닙니다.
사용자가 어떤 보조 그룹에 속해 있는지 언제든지 확인할 수 있습니다.
id -gn username
Bash를 통해 다음을 사용할 수 있습니다.
groups=" $(id -gn "$user") "
if [ "${groups// foo / }" != "$groups" ]; then
# user $user is a member of group foo
else
# user $user is not a member of group foo
fi
사용자가 $user
그룹의 구성원인지 확인하십시오 foo
. (다시 말하지만, 이는 기본 그룹이 아닌 보조 그룹만 확인합니다. 각 사용자는 를 사용하여 얻을 수 있는 기본 그룹을 갖습니다 id -Gn "$user"
.)
이는 선행 및 후행 공백을 사용하여 $groups
공백으로 구분된 사용자 보조 그룹 목록으로 먼저 설정되기 때문에 작동합니다 .$user
인용문을 참고하세요!Bash 표현식은 ${groups// foo / }
값으로 확장 $groups
되지만모두(선행 및 후행 공백 참고) 의 인스턴스가 foo
제거되었습니다(공백으로 대체).
이 절은 if
삭제된 값 $groups
과 제거된 값을 foo
비교합니다 $groups
. 두 가지가 다른 경우에는 $group
포함되어야 합니다 foo
. 이것이 마음에 들지 않으면 동등한 것을 사용할 수 있습니다
if id -Gn "$user" | tr -s ' \n' '\n\n' | grep -qxF foo ; then
# user "$user" is a member of group foo
fi
여기에서는 tr
모든 연속 공백과 개행 문자가 개행 문자로 그룹화되어 그룹 이름이 자체 줄로 분할됩니다. grep -qxF foo
"조용한" grep( )을 수행합니다 . 즉, 아무것도 출력하지 않고 성공 또는 실패만 반환 합니다 -q
(Bash와 같은 파이프 명령에서 성공/실패는 파이프의 마지막 명령에 의해 결정됩니다). -x
우리는 모든 그룹을 받아들이지는 않습니다가지다 foo
그 중에서 단체만정확히 일치 foo
); 마지막으로 -F
옵션은 정규식이 아닌 고정 문자열로 grep
해석됩니다 . foo
( foo
정규식에 특별한 의미를 갖는 문자(예 *
: [
, 등)를 포함하는 ]
경우에만 중요합니다 .)
질문에 설명된 Bash 스크립트를 작성하려면 위의 일부가 필요합니다. 위의 일부를 사용하여 이에 접근하는 두 가지 이상의 다른 방법이 있습니다. 또한 일종의 "각 입력을 변수로 읽어들이는" 루프, 즉
some command | while read line ; do
# Here, "$line" iterates through the lines
# output by some command
done