awk 내에 파일이 있는지 어떻게 확인합니까? [-d 'filename'] 실패


10

존재하지 않는 홈 디렉토리 세트를 가진 사용자 목록을 생성하려고합니다. awk 로이 작업을 수행 할 수 있어야하지만 구문에 문제가 있습니다.

]에서 "잘못된 구문"이라고 계속 알려줍니다. 내가 무엇을 잘못하고 있지?

awk -F: '{ if(![ -d "$6"]){ print $1 " " $3 " " $7}}' /etc/passwd

아마도 내가 사용하게 될 최종 코드는 다음과 같습니다.

awk -F: '{if(system( "[ -d " $6 " ]") == 1 && $7 != "/sbin/nologin" ) {print "The directory " $6 " does not exist for user " $1 }}' /etc/passwd

그리고 관련 질문이 있습니다 .

답변:


14

당신은 사용할 수 있습니다

system (command) 
    운영 체제 명령 명령을 실행 한 다음
    awk 프로그램으로 돌아갑니다. 명령 의 종료 상태를 반환 합니다. 

예 :

awk -F: '{if(system("[ ! -d " $6 " ]") == 0) {print $1 " " $3 " " $7}}' /etc/passwd

어떤 이유로 든 작동시키지 못했습니다. awk '{if (system ( "stat"$ 0 "> / dev / null 2> / dev / null") == 1) print $ 0 } '
Alexander Kjäll

1
@ AlexanderKjäll-이것은 디렉토리의 존재를 테스트-만약 당신이 일반 파일 이 존재 하는지 확인하려고한다면 위의 코드가 실패 할 것입니다 ...
don_crissti

3
이것은 매우 위험합니다! 입력에 따라 임의의 명령이 실행될 수 있습니다 . 예를 들면 다음과 같습니다 /bin/ls. echo ';ls;' | awk '{ print system("[ ! -d " $1 " ]") }'
Tino

6

나는 그렇게 생각하지 않는다 [ -d ]awk쉘 일이 것. 대신이 방법을 대신 사용합니다.

awk -F: '{ print $1,$3,$7}' /etc/passwd | 
    while read name uid shell; do 
        [ -d "/home/$name" ] || echo "$name $uid $shell"; 
    done

물론 @Janis가 정확하게 지적했듯이 쉘에서 모든 것을 할 수 있습니다.

while IFS=: read  name x uid x x x shell rest; do
     [ -d "/home/$name" ] || echo "$name $uid $shell" 
done < /etc/passwd

좋아, 실제로 $ 6을 dir로 전달하고 -d $ dir을하고 싶지만 이것은 많은 도움이됩니다. 이제 아무것도 발견되지 않으면 "결과 없음"을 에코하는 방법을 알아 내야합니다. 감사합니다!
Doug

2
이 있습니다 awk실제로 필요하지 않습니다; 어쨌든 쉘을 반복하기 때문에 할 수도 있습니다 while IFS=: read -r name x uid x x x shell rest ; do ... ; done </etc/passwd.
Janis

@Doug 그냥하세요 awk -F: '{print $6}' /etc/passwd | while read dir; do [ -d "$dir" ] || echo "no results for $dir"; done.
terdon

@ 재니스 정말, 좋은 지적, 답변 편집.
terdon

@terdon이 지적했듯이 [ -d "$6"]실제로 awk가 아닌 bash 구문입니다. [일반 구문처럼 보이지만 (bash는 / 리눅스의 더 나은 weirdnesses 중 하나)은 실제로 동의어입니다 test실행 프로그램 (또는 어쩌면 내장 그것의 버전을 강타하고, 단지 괴상하기 위해, 배쉬는 일치해야합니다 ]아무튼 그 '모든 것이 실제로 구문이며 프로그램이 아니라고 생각하도록 오도하는 것 외에 내가 아는 어떤 것도하지 마십시오.) 어쨌든, 그것은 awk가 알고있는 것이 아닙니다. system()bash가 이해되는 bash의 맥락에서 참조하여 액세스 할 수 있는 함수가 필요한 이유
Joe

6

getline 을 사용할 수 있습니다 :

awk 'BEGIN {print getline < "file" < 0 ? "not exists" : "exists"}'

1
이것은 안전 awk하지만 불행히도 디렉토리에서는 작동하지 않습니다.
Tino

5

실제로 사용 하는 경우 ( 또는을 gawk사용 하는 경우에도 적용되지 않지만) 로드 가능한 확장 중 하나를 사용하여 기본적 으로이 작업을 수행 할 수 있습니다nawkmawk 버전 4.0 이후 사용할 수 있습니다. 나는 사용하고있다 gawk-4.1.x(v4.0은 확장을로드하는 구문에 변형이 있었다).

filefuncs확장 기능을 로드하면 다음과 같은 기능이 추가 stat()됩니다.

@load "filefuncs"
BEGIN {FS=":"}
(NF==7) {
   printf("user: %s %i %i\n",$1,$3,$4)
   rc=stat($6,fstat)
   err=ERRNO  # ERRNO is a string, not an int!
   if (rc<0) { 
       printf(" error: %s rc=%i %s\n",$6,rc,err)
   } else {
      if (fstat["type"]!="directory") 
        printf("  ENOTDIR: %s %s\n",$6,fstat["type"])
      if (fstat["uid"]!=$3) 
        printf("  uid mismatch: %s %i!=%i\n",$6,fstat["uid"],$3)
      if (fstat["gid"]!=$4) 
        printf("  gid mismatch: %s %i!=%i\n",$6,fstat["gid"],$4)
   }
}

참조 filefuncs(3am)이 확장에 대한 자세한 맨 페이지를 .

다음과 같이 실행하십시오.

gawk -f testhome.awk <(getent passwd)    # bash/zsh and glibc
gawk -f testhome.awk /etc/passwd

gawk바이너리가 다음과 같은 확장을 지원 하는지 확인할 수 있습니다 .

BEGIN { 
  if (!("api_major" in PROCINFO)) 
    printf("No extension API.\n")
  else
    printf("Extension API v%s.%s.\n",PROCINFO["api_major"],PROCINFO["api_minor"])
}

따로 : gawk또한 passwd파일 을 읽을 수있는 작은 라이브러리 함수가 제공되며 다음과 같이 호출 할 수 있습니다.

gawk -i passwd.awk -- 'BEGIN { while(uu=getpwent()) {print uu;} endpwent(); }'

getentnsswitch를 지원하므로 Linux / glibc 시스템 에서 사용하는 것을 선호합니다 .


1
흥미 롭군 나는 gawkv4가 이것을 제공하는 것을 몰랐다 . 감사!
Tino

3

거의 어색하다 ...

perl -F: -ane 'if(!-d $F[5]){ print "$F[0] $F[2] $F[6]" }' /etc/passwd

0

여기에 해결책이 있습니다

  • 사용 gawk하고/bin/sh
  • 외부 명령으로 디렉토리를 확인합니까?
  • 그러나 안전하고 안전한 방법입니까

암호:

gawk -F: '{
    cmd="IFS=\"\" read -r dir; [ -d \"$dir\" ]; echo $?";
    print $6 |& cmd;
    cmd |& getline x;
    close(cmd);
    if (x) print x " " $1 " " $3 " " $7
}' /etc/passwd

설명 :

  • IFS="" read -r dir; [ -d "$dir" ]; echo $?stdin에서 경로를 읽고 0디렉토리 인 경우 출력하는 쉘 코드입니다.1
  • print $6 |& cmd파일 이름을 명령으로 파이프합니다. |&GNU-awk 확장입니다.
  • cmd |& getline x 명령 출력을 GNU-awk로 읽습니다.
  • close(cmd) 명령을 마치면 다음 줄이 다시 실행될 수 있습니다.
  • if (x)print그렇지 x않은 경우에만 실행 0(디렉토리가 존재하지 않음)

그러나 매우 느리고 서툴기 때문에이 방법을 사용하지 않는 것이 좋습니다. 하지만 이 레시피는 안전합니다 하므로 불규칙한 입력은 해를 끼치 지 않습니다. ( /etc/passwd유해한 데이터 가 포함되어 있지는 않지만 신뢰할 수없는 출처의 데이터와 함께 사용하려고합니다.)

를 사용할 수 없으면 gawk불행한 일입니다. 이 경우에는 없습니다 |&. 보통 awk다음 세 가지 중 하나만 수행 할 수 있습니다.

  • print "data" | cmd; close(cmd): 데이터를 명령으로 파이프
  • getline data < cmd; close(cmd): 명령에서 데이터 읽기
  • ret = system(cmd): 명령의 리턴 코드를 가져옵니다.

"표준" awk 단순히 데이터를 스크립트로 파이프하고 동시에 무언가를 다시 가져올 수 없습니다 (적어도 나는 방법을 찾지 못했습니다). 더 서투른 중간 파일 (tempfile)이 필요합니다.

흥미로운 관찰은 쉘만으로도 쉬운 작업을 수행 할 수 있다는 것입니다.

dump_problems()
{
have=0;
while IFS=: read -r user pw id grp gcos dir shl;
do
  [ -d "$dir" ] && continue;
  echo "$user $id $shl";
  have=1;
done </etc/passwd;
return $have;
}

dump_problems && echo ALL OK >&2 || echo "Problems were found" >&2

당신은 필요가 없습니다 bash각 정상 Bourne의 쉘 코드 위에 실행할 수 있습니다.

위의 셸 코드는 실제로 필요한 것보다 조금 더 정교하지만, 이것이 실제로 어떻게 작동하는지에 대한 포인터가 될 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.