지난 15일 동안 로그인하지 않은 사용자를 식별하는 스크립트를 만듭니다.

지난 15일 동안 로그인하지 않은 사용자를 식별하는 스크립트를 만듭니다.

질문이 있습니다:

운동은 다음과 같습니다

지난 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

위에서 세 번째 인수를 지정하면 해당 항목만 표시됩니다. ( shadowgshadow도 있지만 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

관련 정보