यदि कोई फ़ाइल awk के भीतर मौजूद है, तो आप कैसे जांचें? [-d 'फ़ाइलनाम'] विफल होना


10

मैं उन उपयोगकर्ताओं की एक सूची तैयार करने की कोशिश कर रहा हूं जिनके पास एक घरेलू निर्देशिका सेट है जो मौजूद नहीं है। ऐसा लगता है कि मुझे जागने में सक्षम होना चाहिए, लेकिन मेरे वाक्यविन्यास में कुछ गड़बड़ है।

यह मुझे "अमान्य सिंटैक्स" पर बताता रहता है। मैं क्या गलत कर रहा हूं?

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 (कमांड) 
    ऑपरेटिंग-सिस्टम कमांड कमांड निष्पादित करें और फिर
    जाग कार्यक्रम पर लौटें। वापसी आदेश से बाहर निकलने की स्थिति। 

उदाहरण के लिए:

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

मुझे यह किसी कारण से काम करने के लिए नहीं मिला, इसलिए मुझे यह करना पड़ा: awk '{if (सिस्टम ("स्टेट" $ 0 "> / dev / null 2> / dev / null") == 1) प्रिंट $ 0 } '
अलेक्जेंडर 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

ठीक है, मुझे लगता है कि मैं वास्तव में dir के रूप में $ 6 पास करना चाहता हूं, और do-d $ dir है, लेकिन इससे बहुत मदद मिलती है। अब मुझे केवल यह पता लगाना है कि यदि कोई नहीं मिलता है तो "कोई परिणाम नहीं" गूँजता है। धन्यवाद!
डग

2
ध्यान दें कि awkवास्तव में जरूरत नहीं है; चूंकि आप शेल में लूप करते हैं, वैसे भी आप बस कर सकते हैं while IFS=: read -r name x uid x x x shell rest ; do ... ; done </etc/passwd
Janis

@ डग बस करो awk -F: '{print $6}' /etc/passwd | while read dir; do [ -d "$dir" ] || echo "no results for $dir"; done
terdon

@ जानिस वास्तव में, अच्छी बात है, जवाब संपादित।
terdon

जैसा कि @terdon के नोट हैं, [ -d "$6"]वास्तव में बैश सिंटैक्स है, awk नहीं। [सामान्य वाक्य रचना की तरह दिखता है, लेकिन (बैश / लिनक्स के बेहतर weirdnesses में से एक में) यह वास्तव में के लिए एक पर्याय है testनिष्पादन योग्य प्रोग्राम (या शायद एक पार्टी में निर्मित यह संस्करण, और, बस weirder हो सकता है, बैश एक मिलान की आवश्यकता है ]कि नहीं करता है 'मैं ऐसा कुछ भी नहीं कर रहा हूँ जिसके बारे में मुझे पता है कि आपको यह गुमराह करने के अलावा कि पूरी बात वास्तव में वाक्य रचना है और एक कार्यक्रम नहीं है)। किसी भी मामले में, यह कुछ अजीब नहीं है जिसके बारे में पता है। इसलिए आपको system()इसे बैश के संदर्भ में इसे समझने के लिए फ़ंक्शन की आवश्यकता है, जहां यह समझा जाता है
जो

6

आप गेटलाइन का उपयोग कर सकते हैं :

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

1
यह सुरक्षित है awk, लेकिन दुर्भाग्य से यह निर्देशिकाओं के लिए काम नहीं करता है।
टीनो

5

यदि आप वास्तव में उपयोग कर रहे हैं gawk(हालांकि आप उपयोग कर रहे हैं nawk, या mawk, जिस स्थिति में यह लागू नहीं होगा), आप मूल रूप से v4.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(); }'

मैं getentLinux / glibc सिस्टम पर उपयोग करना पसंद करता हूं क्योंकि यह nsswitch का समर्थन करता है।


1
दिलचस्प। मैं gawkv4 प्रस्तावों के बारे में पता नहीं था । धन्यवाद!
टीनो

3

यह लगभग awk है ...

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 $?एक शेल कोड है जो स्टडिन और आउटपुट से एक पथ को पढ़ता है 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बस एक स्क्रिप्ट में डेटा को पाइप नहीं कर सकता है और एक ही समय में फिर से कुछ प्राप्त कर सकता है (कम से कम मुझे इसके लिए कोई रास्ता नहीं मिला), इसलिए आपको कुछ मध्यवर्ती फ़ाइल (टेम्पपाइल) की आवश्यकता है जो और भी अधिक अनाड़ी है।

दिलचस्प अवलोकन यह है कि इस तरह के एक आसान कार्य को केवल शेल के साथ किया जा सकता है:

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, प्रत्येक सामान्य बॉर्न-शेल कोड के ऊपर निष्पादित कर सकता है।

ध्यान दें कि उपरोक्त शेल कोड वास्तव में आवश्यक से थोड़ा अधिक विस्तृत है, लेकिन यह इस पर एक संकेतक होगा कि वास्तव में इसके साथ कैसे काम करना है (लोगों के लिए पूरी तरह से अनुभव नहीं है कि शेल कैसे काम करता है)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.