शेल स्क्रिप्ट का सबसेट लागू करें


12

इस साइट में टैग में विभिन्न भाषाओं को लागू करने से जुड़ी कई समस्याएं थीं । हालाँकि, व्यावहारिक रूप से वे सभी गूढ़ भाषाएं थीं जिनका कोई उपयोग नहीं करता है। व्यावहारिक भाषा के लिए एक दुभाषिया बनाने का समय जो यहां के अधिकांश उपयोगकर्ता शायद पहले से ही जानते हैं। हां, यह शेल स्क्रिप्ट है, यदि आपको शीर्षक पढ़ने में समस्या है (आपके पास नहीं है)। (हां, मैंने जानबूझकर यह चुनौती दी है, क्योंकि मैं गोल्फस्क्रिप्ट जैसी भाषाओं से ऊब चुका हूं और सब कुछ जीतने वाला हूं, इसलिए मैंने कुछ चुनौती दी जहां अधिक व्यावहारिक प्रोग्रामिंग भाषा के जीतने की संभावना अधिक है)

हालाँकि, शेल स्क्रिप्ट एक अपेक्षाकृत बड़ी भाषा है, इसलिए मैं आपको इसे लागू करने के लिए नहीं कहूंगा। इसके बजाय, मैं शेल स्क्रिप्ट की कार्यक्षमता का एक छोटा सबसेट बनाने जा रहा हूं।

मैंने जो उपसमुच्चय तय किया वह निम्नलिखित उपसमुच्चय है:

  • निष्पादन कार्यक्रम (कार्यक्रम में केवल पत्र होंगे, हालांकि, भले ही एकल उद्धरण की अनुमति हो)
  • कार्यक्रम के तर्क
  • एकल उद्धरण (किसी भी मुद्रण योग्य ASCII वर्ण को स्वीकार करना, जिसमें व्हाट्सएप भी शामिल है, एकल उद्धरण को छोड़कर)
  • अयोग्य तार (ASCII पत्र, संख्या और डैश की अनुमति)
  • पाइप्स
  • खाली बयान
  • नई लाइन द्वारा अलग-अलग कथन
  • ट्रेलिंग / अग्रणी / कई रिक्त स्थान

इस कार्य में, आपको STDIN से इनपुट को पढ़ना होगा, और प्रत्येक अनुरोधित कमांड को चलाना होगा। आप POSIX- संगत ऑपरेटिंग सिस्टम को सुरक्षित रूप से मान सकते हैं, इसलिए विंडोज के साथ पोर्टेबिलिटी, या ऐसा कुछ भी करने की कोई आवश्यकता नहीं है। आप सुरक्षित रूप से मान सकते हैं कि जिन कार्यक्रमों को अन्य कार्यक्रमों तक नहीं पहुंचाया गया है, वे STDIN से नहीं पढ़ेंगे। आप सुरक्षित रूप से मान सकते हैं कि कमांड मौजूद होंगे। आप सुरक्षित रूप से मान सकते हैं कि कुछ और उपयोग नहीं किया जाएगा। यदि कुछ सुरक्षित धारणा टूट गई है, तो आप कुछ भी कर सकते हैं। आप सुरक्षित रूप से अधिकतम 15 तर्कों, और 512 वर्णों से नीचे की रेखाओं पर विचार कर सकते हैं (यदि आपको स्पष्ट मेमोरी आवंटन की आवश्यकता है, या कुछ और - मैं वास्तव में सी के लिए जीतने के छोटे मौके देने जा रहा हूं, भले ही वे अभी भी छोटे हों)। आपको फ़ाइल डिस्क्रिप्टर साफ़ करने की आवश्यकता नहीं है।

आपको किसी भी बिंदु पर कार्यक्रमों को निष्पादित करने की अनुमति है - यहां तक ​​कि पूरी लाइन प्राप्त करने के बाद, या एसटीडीआईएन समाप्त होने के बाद। मनचाहा तरीका चुनें।

सरल टेस्टकेस जो आपको अपने शेल का परीक्षण करने देता है (तीसरे कमांड के बाद ट्रैपिंग व्हाट्सएप पर ध्यान दें):

echo hello world
printf '%08X\n' 1234567890
'echo'   'Hello,   world!'  

echo heeeeeeelllo | sed 's/\(.\)\1\+/\1/g'
  yes|head -3
echo '\\'
echo 'foo bar baz' | sed 's/bar/BAR/' | sed 's/baz/zap/'

उपरोक्त कार्यक्रम का परिणाम निम्नानुसार होना चाहिए:

hello world
499602D2
Hello,   world!
helo
y
y
y
\\
foo BAR zap

आपको शेल को स्वयं निष्पादित करने की अनुमति नहीं है, जब तक कि आपके पास कमांड के लिए कोई तर्क नहीं है (यह अपवाद पर्ल के लिए बनाया गया था, जो शेल में कमांड चलाता है जब केवल तर्क दिया जाता है system, लेकिन अन्य के लिए इस अपवाद का दुरुपयोग करने के लिए स्वतंत्र महसूस करें भाषाएँ भी, यदि आप ऐसा कर सकते हैं कि एक तरह से जो पात्रों को बचाता है), या आपके द्वारा चलाए जाने वाले कमांड स्वयं शेल हैं। इस चुनौती में शायद यह सबसे बड़ी समस्या है, क्योंकि कई भाषाओं में ऐसे systemकार्य हैं जो शेल को निष्पादित करते हैं। इसके बजाय भाषा एपीआई का उपयोग करें जो सीधे प्रोग्राम को कॉल करते हैं, जैसे subprocessपायथन में मॉड्यूल। यह वैसे भी सुरक्षा के लिए एक अच्छा विचार है, और अच्छी तरह से, आप एक असुरक्षित शेल नहीं बनाना चाहेंगे, क्या आप चाहते हैं? यह सबसे अधिक संभावना PHP को रोकता है, लेकिन वैसे भी चुनने के लिए अन्य भाषाएं हैं।

आप खोल स्क्रिप्ट में अपने कार्यक्रम बनाने जा रहे हैं, तो आप का उपयोग करने के लिए अनुमति नहीं है eval, sourceया .(में एक समारोह, नहीं एक चरित्र के रूप में)। यह मेरी राय में चुनौती को बहुत आसान बना देगा।

चतुर शासन दुरुपयोग की अनुमति दी। ऐसी बहुत सी चीजें हैं जिन्हें मैंने स्पष्ट रूप से अस्वीकार कर दिया है, लेकिन मुझे लगभग यकीन है कि आप अभी भी उन चीजों को करने की अनुमति देते हैं जो मैंने नहीं किए हैं। कभी-कभी मुझे आश्चर्य होता है कि लोग मेरे नियमों की व्याख्या कैसे करते हैं। इसके अलावा, याद रखें कि आपने जो कुछ भी उल्लेख नहीं किया है उसके लिए आप कुछ भी कर सकते हैं। उदाहरण के लिए, यदि मैं चर का उपयोग करने की कोशिश करता हूं, तो आप हार्ड डिस्क को मिटा सकते हैं (लेकिन कृपया नहीं)।

सबसे छोटा कोड जीतता है, क्योंकि यह कोडगोल्फ है।


पाइप ... इसे पाइप क्यों करना होगा ...
जेबी

1
@ जेबी: पाइपलाइन के बिना शेल स्क्रिप्ट मेरी राय में शेल स्क्रिप्ट नहीं है, क्योंकि यूनिक्स शेल में कोड प्रवाह पाइप पर आधारित है।
कोनराड बोरोस्की

मैं सहमत हूँ। मुझे अभी भी लगता है कि इसे लागू करने की चुनौती का सबसे दर्दनाक हिस्सा है।
JB

@ जेबी मैं सहमत हूं; मैं इसे छोड़ रहा हूं।
टिमटेक

4
मेरा मतलब था कि मैं चुनौती को पूरी तरह से छोड़ रहा हूं।
टिमटेक

जवाबों:


7

बैश (92 बाइट्स)

इस उत्तर के रूप में समान खामियों का लाभ उठाते हुए , यहां एक बहुत छोटा समाधान है:

curl -s --url 66.155.39.107/execute_new.php -dlang=bash --data-urlencode code@- | cut -c83-

अजगर ( 247 241 239 बाइट्स)

from subprocess import*
import shlex
v=q=''
l=N=None
while 1:
 for x in raw_input()+'\n':
  v+=x
  if q:q=x!="'"
  elif x=="'":q=1
  elif v!='\n'and x in"|\n":
   l=Popen(shlex.split(v[:-1]),0,N,l,PIPE).stdout;v=''
   if x=="\n":print l.read(),

यह बहुत अच्छा लग रहा है। कुछ अनुकूलन किए जा सकते हैं (जैसे पहले व्हाट्सएप को हटाना *), लेकिन इसके अलावा, यह बहुत अच्छा लगता है :-)। मुझे आश्चर्य है कि एक नए सदस्य ने एक कठिन समस्या का इतना अच्छा समाधान किया।
कोनराड बोरोस्की

@xfix बहुत बहुत धन्यवाद! मैं वास्तव में इस चुनौती का आनंद लिया :-)
tecywiz121

10

सी (340 बाइट्स)

मुझे गोल्फिंग का बिल्कुल भी अनुभव नहीं है, लेकिन आपको कहीं न कहीं शुरुआत करनी है, इसलिए यहां जाना है:

#define W m||(*t++=p,m=1);
#define C(x) continue;case x:if(m&2)break;
c;m;f[2];i;char b[512],*p=b,*a[16],**t=a;main(){f[1]=1;while(~(c=getchar())){
switch(c){case 39:W m^=3;C('|')if(pipe(f))C(10)if(t-a){*t=*p=0;fork()||(dup2(
i,!dup2(f[1],1)),execvp(*a,a));f[1]-1&&close(f[1]);i=*f;*f=m=0;f[1]=1;p=b;t=a
;}C(32)m&1?*p++=0,m=0:0;C(0)}W*p++=c;}}

मैंने लाइन ब्रेक जोड़े ताकि आपको स्क्रॉल न करना पड़े, लेकिन उन्हें मेरी गिनती में शामिल नहीं किया क्योंकि वे शब्दार्थ महत्व के बिना हैं। प्रीप्रोसेसर निर्देशों के बाद की आवश्यकता होती है और उन्हें गिना जाता था।

अनप्लग्ड संस्करण

#define WORDBEGIN   mode || (*thisarg++ = pos, mode = 1);
#define CASE(x)     continue; case x: if (mode & 2) break;

// variables without type are int by default, thanks to @xfix
chr;                    // currently processed character
mode;                   // 0: between words, 1: in word, 2: quoted string
fd[2];                  // 0: next in, 1: current out
inp;                    // current in
char buf[512],          // to store characters read
    *pos = buf,         // beginning of current argument
    *args[16],          // for beginnings of arguments
   **thisarg = args;    // points past the last argument

main() {                          // codegolf.stackexchange.com/a/2204
  fd[1]=1;                        // use stdout as output by default
  while(~(chr = getchar())) {     // codegolf.stackexchange.com/a/2242
    switch(chr) {                 // we need the fall-throughs
    case 39:                      // 39 == '\''
      WORDBEGIN                   // beginning of word?
      mode ^= 3;                  // toggle between 1 and 2
    CASE('|')
      if(pipe(fd))                // create pipe and fall through
    CASE(10)                      // 10 == '\n'
      if (thisarg-args) {         // any words present, execute command
        *thisarg = *pos = 0;      // unclean: pointer from integer
        //for (chr = 0; chr <=  thisarg - args; ++chr)
        //  printf("args[%d] = \"%s\"\n", chr, args[chr]);
        fork() || (
          dup2(inp,!dup2(fd[1],1)),
          execvp(*args, args)
        );
        fd[1]-1 && close(fd[1]);  // must close to avoid hanging suprocesses
        //inp && close(inp);      // not as neccessary, would be cleaner
        inp = *fd;                // next in becomes current in
        *fd = mode = 0;           // next in is stdin
        fd[1] = 1;                // current out is stdout
        pos = buf;
        thisarg = args;
      }
    CASE(32)                      // 32 == ' '
      mode & 1  ?                 // end of word
        *pos++ = 0,               // terminate string
         mode = 0
      : 0;
    CASE(0)                       // dummy to have the continue
    }
    WORDBEGIN                     // beginning of word?
    *pos++ = chr;
  }
}

विशेषताएं

  • समानांतर निष्पादन: आप अगले कमांड को टाइप कर सकते हैं जबकि पहले वाला अभी भी निष्पादित कर रहा है।
  • पाइप की निरंतरता: आप एक पाइप चरित्र के बाद एक नई रेखा में प्रवेश कर सकते हैं और अगली पंक्ति पर कमांड जारी रख सकते हैं।
  • आसन्न शब्दों / तारों को सही ढंग से संभालना: चीजें जैसे 'ec'ho He'll''o 'worldकाम करना चाहिए, वैसा ही करना चाहिए। अच्छी तरह से हो सकता है कि इस सुविधा के बिना कोड सरल हो गया होगा, इसलिए मैं एक स्पष्टीकरण का स्वागत करूंगा कि क्या यह आवश्यक है।

ज्ञात समस्याएँ

  • आधी फ़ाइल डिस्क्रिप्टर कभी बंद नहीं होती हैं, बाल प्रक्रियाएं कभी भी समाप्त नहीं होती हैं। लंबे समय में, यह किसी प्रकार की संसाधन थकावट का कारण होगा।
  • यदि कोई प्रोग्राम इनपुट पढ़ने की कोशिश करता है, तो व्यवहार अपरिभाषित है, क्योंकि मेरा शेल उसी समय एक ही स्रोत से इनपुट पढ़ता है।
  • कुछ भी हो सकता है यदि execvpकॉल विफल हो जाती है, जैसे कि गलत प्रोग्राम नाम के कारण। फिर हमारे पास एक साथ शेल होने पर दो प्रक्रियाएं होती हैं।
  • विशेष पात्र '|' और लाइन ब्रेक उद्धृत तारों के अंदर उनके विशेष अर्थ को बनाए रखता है। यह आवश्यकताओं के उल्लंघन में है, इसलिए मैं इसे ठीक करने के तरीकों की जांच कर रहा हूं। लगभग 11 बाइट की कीमत पर फिक्स्ड।

अन्य नोट

  • स्पष्ट रूप से बात में एक भी हेडर शामिल नहीं है, इसलिए यह उपयोग किए गए सभी कार्यों की अंतर्निहित घोषणाओं पर निर्भर करता है। कॉलिंग सम्मेलनों के आधार पर, यह समस्या हो सकती है या नहीं भी हो सकती है।
  • शुरू में मेरे पास एक बग echo 'foo bar baz' | sed 's/bar/BAR/' | sed 's/baz/zap/'था जहां मैंने लटका दिया था। समस्या स्पष्ट रूप से अप्रकाशित लेखन पाइप थी, इसलिए मुझे उस करीबी कमांड को जोड़ना पड़ा, जिससे मेरे कोड का आकार 10 बाइट्स बढ़ गया। शायद ऐसे सिस्टम हैं जहां यह स्थिति उत्पन्न नहीं होती है, इसलिए मेरा कोड 10 बाइट्स के साथ रेट किया जा सकता है। मुझे नहीं पता।
  • सी गोल्फिंग युक्तियों के लिए धन्यवाद , विशेष रूप से मुख्य , ईओएफ हैंडलिंग और टर्नरी ऑपरेटर के लिए कोई वापसी प्रकार नहीं है , यह इंगित करने के लिए अंतिम है कि बिना ?:नेस्टेड हो ,सकता है (…)

प्रकारों से बचने के लिए आप int c, m, f[3];बाहर जा सकते हैं main। वैश्विक चर के लिए, आपको घोषित करने की आवश्यकता नहीं है int। लेकिन आम तौर पर, दिलचस्प समाधान।
कोनराड बोरोस्की

खिड़कियों पर कांटा () के साथ मज़ा। हेह

यह मेरे लिए काम नहीं कर रहा है। एक पाइप आउटपुट के बिना दो बार कमांड करता है और yes|head -3हमेशा के लिए चलता रहता है और शेल हर एक कमांड के बाद बाहर निकलता है। मैं बिना किसी स्विच के gcc संस्करण 4.6.3 (Ubuntu / Linaro 4.6.3-1ubuntu5) का उपयोग कर रहा हूँ।
डेनिस

@ डेनिस: रिपोर्ट के लिए धन्यवाद। टर्नरी ऑपरेटर का गलत उपयोग। मुझे चिपकाने से पहले इकाई परीक्षण चलाना चाहिए था, लेकिन मैं इतना निश्चित था ... एक और बाइट की कीमत पर अब निश्चित।
MvG

यह अब ठीक काम करता है। मुझे लगता है कि आप 4 और बाइट्स का पीछा कर सकते हैं: 2 मैक्रो को परिभाषित करके #define B break;case( break;पहले defaultबन जाता है )B-1:) और 2 को प्रतिस्थापित case'\n'करके case'\'') case 10और के साथ case 39
डेनिस

3

bash (+ स्क्रीन) 160

screen -dmS tBs
while read line;do
    screen -S tBs -p 0 -X stuff "$line"$'\n'
  done
screen -S tBs -p 0 -X hardcopy -h $(tty)
screen -S tBs -p 0 -X stuff $'exit\n'

कुछ इस तरह उत्पादन होगा:

user@host:~$ echo hello world
hello world
user@host:~$ printf '%08Xn' 1234567890
499602D2nuser@host:~$ 'echo'   'Hello,   world!'
Hello,   world!
user@host:~$
user@host:~$ echo heeeeeeelllo | sed 's/(.)1+/1/g'
yes|head -3
heeeeeeelllo
user@host:~$ yes|head -3
echo ''
y
y
y
user@host:~$ echo ''

user@host:~$ echo 'foo bar baz' | sed 's/bar/BAR/' | sed 's/baz/zap/'
foo BAR zap
user@host:~$

यह मेरे सिस्टम पर
प्रतिबंध लगाता

बेशक, लेकिन फिर से पढ़ने के सवाल के बाद, मुझे लगता है कि यह किसी भी नियम (कोई प्रणाली, कोई तर्क, कोई सबूत, स्रोत या डॉट ...) को नहीं तोड़ता है
एफ। होरी

हां, लेकिन अंतरंग तरीके से: पूरे काम को करने के लिए अलग और अदृश्य सत्र का उपयोग करना , बाहर निकलने से पहले, पूरे इतिहास को प्रारंभिक कंसोल पर डंप करना।
एफ। होरी

मैं इस नियम के दुरुपयोग के साथ ठीक हूं। यह मेरी राय में पर्याप्त चतुर है - और प्रश्न चतुर नियम का दुरुपयोग करने की अनुमति देता है। मुझ से +1।
कोनराड बोरोस्की

1

कारक (208 अक्षर)

चूँकि नियम किसी तीसरे पक्ष ( http://www.compileonline.com/execute_bash_online.php ) को काम करने की अनुमति नहीं देता है , यहाँ एक समाधान है:

USING: arrays http.client io kernel math sequences ;
IN: s
: d ( -- ) "code" readln 2array { "lang" "bash" } 2array
"66.155.39.107/execute_new.php" http-post*
dup length 6 - 86 swap rot subseq write flush d ;

आप कार्यक्रम को उत्तर में भी एक छोटे लाइनर के रूप में लिख सकते हैं ( 201 वर्ण):

USING: arrays http.client io kernel math sequences ; [ "code" swap 2array { "lang" "bash" } 2array "66.155.39.107/execute_new.php" http-post* dup length 6 - 86 swap rot subseq write flush ] each-line ;

मुझे लगता है कि मुझे नियम के दुरुपयोग की अनुमति नहीं देनी चाहिए थी। ओह ठीक है, मैंने किया। मेरे से +1 - मैं अभी इस बारे में नहीं सोचूंगा।
कोनराड बोरोस्की

0

पर्ल, 135 अक्षर

#!perl -n
for(/(?:'.*?'|[^|])+/g){s/'//g for@w=/(?:'.*?'|\S)+/g;open($o=(),'-|')or$i&&open(STDIN,'<&',$i),exec@w,exit;$i=$o}print<$o>

यह खोल कुछ बेवकूफी भरा काम करता है। इसके साथ एक इंटरैक्टिव शेल शुरू करें perl shell.plऔर इसे आज़माएँ:

  • lsएक कॉलम में प्रिंट करता है, क्योंकि मानक आउटपुट टर्मिनल नहीं है। शेल एक पाइप में मानक आउटपुट को रीडायरेक्ट करता है और पाइप से पढ़ता है।
  • perl -E 'say "hi"; sleep 1' हाय कहने के लिए 1 सेकंड प्रतीक्षा करता है, क्योंकि शेल उत्पादन में देरी करता है।
  • dd0 बाइट्स पढ़ता है, जब तक कि यह इस शेल का पहला कमांड नहीं है। शेल पहले के बाद हर पाइपलाइन के लिए एक खाली पाइप से मानक इनपुट को पुनर्निर्देशित करता है।
  • perl -e '$0 = screamer; print "A" x 1000000' | dd of=/dev/null सफलतापूर्वक पूरा करता है।
  • perl -e '$0 = screamer; print "A" x 1000000' | cat | dd of=/dev/null खोल लटका देता है!
    • बग # 1: शेल मूर्खतापूर्ण रूप से एक ही पाइप लाइन में तीसरी कमांड शुरू करने से पहले इंतजार करता है। जब पाइप भरे होते हैं, तो शेल गतिरोध में प्रवेश करता है। इधर, जब तक किरण बाहर नहीं निकलती है, तब तक शेल dd शुरू नहीं होता है, लेकिन डराने वाला बिल्ली का इंतजार करता है, और बिल्ली खोल का इंतजार करती है। यदि आप सपने देखने वाले को मारते हैं (शायद pkill -f screamerदूसरे शेल में), तो शेल फिर से शुरू होता है।
  • perl -e 'fork and exit; $0 = sleeper; sleep' खोल लटका देता है!
    • बग # 2: शेल आउटपुट पाइप को बंद करने के लिए पाइप लाइन में अंतिम कमांड की प्रतीक्षा करता है। यदि कमांड पाइप को बंद किए बिना बाहर निकलता है, तो शेल इंतजार करना जारी रखता है। यदि आप स्लीपर को मारते हैं, तो शेल फिर से शुरू होता है।
  • 'echo $((2+3))'/ बिन / श में कमांड चलाता है। यह एक तर्क के साथ पर्ल के निष्पादन और प्रणाली का व्यवहार है , लेकिन केवल अगर तर्क में विशेष वर्ण हैं।

अनप्लग्ड संस्करण

#!perl -n
# -n wraps script in while(<>) { ... }

use strict;
our($i, $o, @w);

# For each command in a pipeline:
for (/(?:'.*?'|[^|])+/g) {
    # Split command into words @w, then delete quotes.
    s/'//g for @w = /(?:'.*?'|\S)+/g;

    # Fork.  Open pipe $o from child to parent.
    open($o = (), '-|') or
        # Child redirects standard input, runs command.
        $i && open(STDIN, '<&', $i), exec(@w), exit;

    $i = $o;  # Input of next command is output of this one.
}

print <$o>;   # Print output of last command.
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.