POSIX sed के लिए `1d; 1,2d` की क्या आवश्यकता है जहां एक पता सीमा पहले से हटाए गए लाइन से शुरू होती है?


11

इस सवाल की टिप्पणियों में एक मामला सामने आया जहां विभिन्न सरल कार्यान्वयन काफी असहमत कार्यक्रम पर असहमत थे, और हम (या कम से कम मैं) यह निर्धारित करने में सक्षम नहीं थे कि इसके लिए वास्तव में विनिर्देश की आवश्यकता क्या है।

समस्या एक विलम्बित रेखा पर शुरू होने वाली श्रेणी का व्यवहार है:

1d;1,2d

क्या लाइन 2 को हटा दिया जाना चाहिए भले ही उस कमांड तक पहुंचने से पहले रेंज की शुरुआत को हटा दिया गया हो? मेरी शुरुआती उम्मीद बीएसडी sed के अनुरूप "नहीं" थी, जबकि GNU sed "हाँ" कहता है, और विनिर्देश पाठ की जाँच पूरी तरह से मामले को हल नहीं करती है।

मेरी अपेक्षा से मेल खाते हैं (कम से कम) macOS और Solaris sed, और BSD sed। असहमत हैं (कम से कम) जीएनयू और बिजीबॉक्स sed, और यहां कई लोग हैं। पहले दो SUS- प्रमाणित हैं, जबकि अन्य संभावित रूप से अधिक व्यापक हैं। कौन सा व्यवहार सही है?


विनिर्देश पाठ दो पता श्रेणी के लिए कहते हैं:

तब सीड यूटिलिटी तब अनुक्रम में लागू होगी, जिनके कमांड अगले चक्र या क्विट शुरू होने तक, जिनके कमांड स्पेस पैटर्न का चयन करते हैं।

तथा

दो पतों वाला एक एडिटिंग कमांड पहले पैटर्न स्पेस से इनक्लूसिव रेंज का चयन करेगा, जो दूसरे पैटर्न से मेल खाने वाले अगले पैटर्न स्पेस के जरिए पहले एड्रेस से मैच करता है। [...] चयनित सीमा के बाद पहली पंक्ति से शुरू होकर, sed पहले पते के लिए फिर से दिखेगा। इसके बाद, इस प्रक्रिया को दोहराया जाएगा।

बेशक, लाइन 2 है भीतर , चाहे प्रारंभ बिंदु हटा दिया गया है, भले ही "पहले पैटर्न अंतरिक्ष कि अगले पैटर्न अंतरिक्ष दूसरे से मेल खाता है के माध्यम से पहली पते से मेल खाता से समावेशी रेंज"। दूसरी ओर, मैंने पहले dचक्र में आगे बढ़ने की उम्मीद की और सीमा को शुरू करने का मौका नहीं दिया। UNIX ™ -certified कार्यान्वयन वही करता है जो मुझे उम्मीद थी, लेकिन संभवतः ऐसा नहीं है जो विनिर्देशन जनादेश।

कुछ इलस्ट्रेटिव एक्सपेरिमेंट फॉलो करते हैं, लेकिन अहम सवाल यह है कि डिलीट लाइन पर रेंज शुरू होने पर क्या करना चाहिए sed ?


प्रयोग और उदाहरण

समस्या का एक सरलीकृत प्रदर्शन यह है, जो लाइनों की अतिरिक्त प्रतियों को हटाने के बजाय प्रिंट करता है:

printf 'a\nb\n' | sed -e '1d;1,2p'

यह sedइनपुट की दो लाइनें प्रदान करता है , aऔर b। कार्यक्रम दो काम करता है:

  1. के साथ पहली पंक्ति हटाता है 1ddआदेश होगा

    पैटर्न स्पेस हटाएं और अगला चक्र शुरू करें। तथा

  2. 1 से 2 तक की पंक्तियों की सीमा का चयन करें और प्रत्येक पंक्ति को प्राप्त होने वाली स्वचालित छपाई के अलावा उन्हें स्पष्ट रूप से प्रिंट करता है। सीमा में शामिल एक पंक्ति इस प्रकार दो बार दिखाई देनी चाहिए।

मेरी अपेक्षा यह थी कि यह छपनी चाहिए

b

केवल, सीमा लागू नहीं होने के कारण क्योंकि 1,2लाइन 1 के दौरान कभी नहीं पहुंचा जाता है (क्योंकि dअगले चक्र / लाइन पर पहले से ही कूद गया है) और इसलिए सीमा शामिल करना कभी भी शुरू नहीं होता है, जबकि aहटा दिया गया है। sedमैकओएस और सोलारिस 10 के अनुरूप यूनिक्स एस इस उत्पादन का उत्पादन करते हैं, जैसा कि sedसोलारिस और बीएसडी sedमें गैर-पॉसिक्स सामान्य रूप से करते हैं।

दूसरी ओर जीएनयू सेड, प्रिंट

b
b

यह दर्शाता है कि इसने रेंज की व्याख्या की है। यह POSIX मोड में होता है और नहीं भी। बिजीबॉक्स के सीड में समान व्यवहार होता है (लेकिन हमेशा समान व्यवहार नहीं होता है, इसलिए यह साझा कोड का परिणाम नहीं लगता है)।

के साथ आगे प्रयोग

printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/c/p'
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/d/p'

यह पाता है कि यह एक हटाई गई रेखा पर शुरू होने वाली सीमा का इलाज करता प्रतीत होता है जैसे कि यह निम्न पंक्ति पर शुरू होता है । यह दृश्यमान है क्योंकि /c/सीमा समाप्त करने के लिए मेल नहीं खाता है। /b/रेंज शुरू करने का उपयोग करने के रूप में ही व्यवहार नहीं करता है 2


प्रारंभिक कार्य उदाहरण मैं उपयोग कर रहा था

printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'

पहले /a/मैच तक सभी लाइनों को हटाने के लिए एक तरीका के रूप में , भले ही वह पहली पंक्ति पर हो (जीएनयू sed किसके 0,/a/dलिए उपयोग करेगा - यह उस का POSIX- संगत प्रतिपादन था)।

यह सुझाव दिया गया है कि इस के बजाय करने के लिए हटा देना चाहिए दूसरे का मैच /a/है, जो प्रशंसनीय लगता है (अगर कोई दूसरा मैच है या पूरी फ़ाइल) पहली पंक्ति मैचों हैं - लेकिन फिर से, केवल जीएनयू sed कि नहीं करता है। दोनों macOS sed और सोलारिस की sed उपज

b
c
d
e

उस के लिए, जैसा कि मुझे उम्मीद थी (GNU sed अनअर्डिनेटेड रेंज को हटाने से खाली आउटपुट पैदा करता है; बिजीबॉक्स sed प्रिंट बस dऔर e, जो स्पष्ट रूप से गलत है कोई फर्क नहीं पड़ता)। आम तौर पर मुझे लगता है कि उनके पास होने के कारण प्रमाणन अनुरूपता परीक्षण का अर्थ है कि उनका व्यवहार सही है, लेकिन पर्याप्त लोगों ने सुझाव दिया है कि मुझे यकीन नहीं है, विनिर्देश पाठ पूरी तरह से आश्वस्त नहीं है, और परीक्षण सूट नहीं हो सकता है पूरी तरह से व्यापक।

स्पष्ट रूप से यह लिखने के लिए व्यावहारिक रूप से पोर्टेबल नहीं है कि आज कोड को असंगति दी गई है, लेकिन सैद्धांतिक रूप से यह एक अर्थ या दूसरे के साथ हर जगह समान होना चाहिए। मुझे लगता है कि यह एक बग है, लेकिन मुझे यह नहीं पता है कि इसे लागू करने के लिए कौन सा कार्यान्वयन है। मेरा विचार वर्तमान में यह है कि GNU और बिजीबॉक्स सेड का व्यवहार विनिर्देश के साथ असंगत है, लेकिन मुझे उस पर गलती हो सकती है।

यहाँ POSIX की क्या आवश्यकता है?


एक अस्थायी वर्कअराउंड के रूप में, एक अस्थायी फ़ाइल पर लिखें और इसे POSIX के साथ संसाधित करें ed, sedपूरी तरह से दरकिनार ?
डी। बेन नोबल

जवाबों:


9

यह मार्च 2012 में ऑस्टिन समूह की मेलिंग सूची पर उठाया गया था। यहां पर उस पर अंतिम संदेश दिया गया है (ऑस्टिन समूह के ज्योफ क्लेर द्वारा (बॉडी जो पोसिक्स को बनाए रखता है), वह भी जिसने पहले मुद्दे को उठाया था। यहाँ gmane NNTP इंटरफ़ेस से कॉपी किया गया है:

Date: Fri, 16 Mar 2012 17:09:42 +0000
From: Geoff Clare <gwc-7882/jkIBncuagvECLh61g@public.gmane.org>
To: austin-group-l-7882/jkIBncuagvECLh61g@public.gmane.org
Newsgroups: gmane.comp.standards.posix.austin.general
Subject: Re: Strange addressing issue in sed

Stephane Chazelas <stephane_chazelas-Qt13gs6zZMY@public.gmane.org> wrote, on 16 Mar 2012:
>
> 2012-03-16 15:44:35 +0000, Geoff Clare:
> > I've been alerted to an odd behaviour of sed on certified UNIX
> > systems that doesn't seem to match the requirements of the
> > standard.  It concerns an interaction between the 'n' command
> > and address matching.
> > 
> > According to the standard, this command:
> > 
> > printf 'A\nB\nC\nD\n' | sed '1,3s/A/B/;1,3n;1,3s/B/C/'
> > 
> > should produce the output:
> > 
> > B
> > C
> > C
> > D
> > 
> > GNU sed does produce this, but certified UNIX systems produce this:
> > 
> > B
> > B
> > C
> > D
> > 
> > However, if I change the 1,3s/B/C/ to 2,3s/B/C/ then they produce
> > the expected output (tested on Solaris and HP-UX).
> > 
> > Is this just an obscure bug from common ancestor code, or is there
> > some legitimate reason why this address change alters the behaviour?
> [...]
> 
> I suppose the idea is that for the second 1,3cmd, line "1" has
> not been seen, so the 1,3 range is not entered.

Ah yes, now it makes sense, and it looks like the standard does
require this slightly strange behaviour, given how the processing
of the "two addresses" case is specified:

    An editing command with two addresses shall select the inclusive
    range from the first pattern space that matches the first address
    through the next pattern space that matches the second.  (If the
    second address is a number less than or equal to the line number
    first selected, only one line shall be selected.) Starting at the
    first line following the selected range, sed shall look again for
    the first address. Thereafter, the process shall be repeated.

It's specified this way because the addresses can be BREs, but if
the same matching process is applied to the line numbers (even though
they can only match at most once), then the 1,3 range on that last
command is never entered.

-- 
Geoff Clare <g.clare-7882/jkIBncuagvECLh61g@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England

और यहाँ संदेश के बाकी हिस्से (मेरे द्वारा) जो कि ज्योफ उद्धृत कर रहे थे:

I suppose the idea is that for the second 1,3cmd, line "1" has
not been seen, so the 1,3 range is not entered.

Same idea as in

printf '%s\n' A B C | sed -n '1d;1,2p'

whose behavior differ in traditional (heirloom toolchest at
least) and GNU.

It's unclear to me whether POSIX wants one behavior or the
other.

तो, (ज्योफ के अनुसार) पोसिक्स स्पष्ट है कि जीएनयू व्यवहार गैर-अनुपालन है।

और यह सच है कि यह कम सुसंगत है (तुलना seq 10 | sed -n '1d;1,2p'करें seq 10 | sed -n '1d;/^1$/,2p') भले ही संभावित रूप से उन लोगों के लिए कम आश्चर्य की बात है जो यह नहीं समझते कि कैसे संसाधित किया जाता है (यहां तक ​​कि ज्योफ ने शुरू में अनुरूप व्यवहार "अजीब" पाया )।

किसी ने इसे GNU लोगों के लिए बग के रूप में रिपोर्ट करने की जहमत नहीं उठाई। मुझे यकीन नहीं है कि मैं इसे बग के रूप में अर्हता प्राप्त करूंगा। संभवतः POSIX विनिर्देशन को अद्यतन करने के लिए दोनों व्यवहारों को स्पष्ट करने की अनुमति देने के लिए सबसे अच्छा विकल्प यह होगा कि कोई भी इस पर भरोसा नहीं कर सकता है।

संपादित करें । मैंने अब sed70 के दशक के उत्तरार्ध से यूनिक्स V7 में मूल कार्यान्वयन पर एक नज़र डाली है, और यह बहुत अधिक ऐसा लगता है जैसे संख्यात्मक पते के लिए व्यवहार का इरादा नहीं था या कम से कम पूरी तरह से वहाँ के माध्यम से नहीं सोचा गया था।

ज्योफ की युक्ति पढ़ने के साथ (और मेरी मूल व्याख्या कि ऐसा क्यों होता है), इसके विपरीत, इसमें:

seq 5 | sed -n '3d;1,3p'

लाइनों 1, 2, 4 और 5 का आउटपुट होना चाहिए, क्योंकि इस बार, यह अंतिम पता है जो कि कभी भी 1,3pक्रमबद्ध कमांड द्वारा सामना नहीं किया गया है , जैसेseq 5 | sed -n '3d;/1/,/3/p'

फिर भी, मूल कार्यान्वयन में ऐसा नहीं होता है, न ही कोई अन्य कार्यान्वयन जो मैंने कोशिश की ( sedव्यस्त बॉक्स 1, 2 और 4 रिटर्न देता है जो बग की तरह दिखता है)।

यदि आप UNIX v7 कोड को देखते हैं , तो यह उस स्थिति के लिए जांच करता है जहां वर्तमान लाइन संख्या (संख्यात्मक) अंत पते से अधिक है, और फिर सीमा से बाहर हो जाती है। यह तथ्य यह है कि यह शुरुआत के पते के लिए ऐसा नहीं करता है एक जानबूझकर डिजाइन की तुलना में अधिक निरीक्षण की तरह दिखता है।

इसका मतलब यह है कि इस समय उस संबंध में POSIX कल्पना की उस व्याख्या के अनुपालन के लिए वास्तव में कोई कार्यान्वयन नहीं है।

GNU कार्यान्वयन के साथ एक और भ्रामक व्यवहार है:

$ seq 5 | sed -n '2d;2,/3/p'
3
4
5

चूंकि लाइन 2 को छोड़ दिया गया था, 2,/3/लाइन 3 (पहली पंक्ति जिसका नंबर> = 2 है) पर दर्ज किया गया है। लेकिन जैसा कि यह रेखा है जिसने हमें सीमा में प्रवेश किया है, यह अंतिम पते के लिए जाँच नहीं है । इसके साथ खराब हो जाता busybox sedहै:

$ seq 10 | busybox sed -n '2,7d; 2,3p'
8

चूँकि 2 से 7 को हटा दिया गया था, पंक्ति 8 वह पहली है जो = = 2 है इसलिए 2,3 श्रेणी में प्रवेश किया जाता है !


1
तो ऐसा लगता है कि यह मुद्दा अभी भी अनसुलझा है - मैं आपके तर्क से सहमत हूं कि ऐसा क्यों हो रहा है, लेकिन यह भी स्पष्ट नहीं है कि क्या यही चाहता था - हालांकि यह भी लगता है कि ज्योफ की तरह यह भी उद्धृत पाठ से आश्वस्त था कि UNIX ™ कार्यान्वयन सही थे। क्या आपका पढ़ना भी उतना ही अच्छा है?
माइकल होमर

1
@MichaelHomer, विचार यह है कि (ज्योफ के अनुसार) POSIX स्पष्ट है कि GNU व्यवहार गैर-अनुपालन योग्य है। और यह सच है कि यह कम सुसंगत है (तुलना seq 10 | sed -n '1d;1,2p'करें seq 10 | sed -n '1d;/^1$/,2p') भले ही संभावित रूप से लोगों को कम आश्चर्य न हो कि सीमाओं को कैसे संसाधित किया जाता है। किसी ने इसे GNU लोगों के लिए बग के रूप में रिपोर्ट करने की जहमत नहीं उठाई। मुझे यकीन नहीं है कि मैं इसे बग के रूप में अर्हता प्राप्त करूंगा, संभवत: सबसे अच्छा विकल्प यह होगा कि दोनों व्यवहारों को स्पष्ट करने के लिए पोसिक्स युक्ति को अपडेट करें ताकि यह स्पष्ट हो सके कि किसी पर भी भरोसा नहीं किया जा सकता है।
स्टीफन चेजलस

2
दरअसल, POSIX परिभाषा के अनुसार कोई विवरण नहीं है कि पते को शुरू करने या पता सीमा को समाप्त करने के लिए "देखे जाने" की आवश्यकता है, IMO GNU कार्यान्वयन पोसिक्स शब्द को अधिक सख्ती से पालन करता है (GNU के लिए आश्चर्यजनक!)। यह उन वास्तविक-विश्व मामलों के लिए वांछित व्यवहार भी है जिन्हें मैं जानता हूं। लेकिन, जैसा कि आप बताते हैं, इसके अनुरूप होना चाहिए। और रेंज पैटर्न के लिए प्रत्येक पंक्ति की जाँच करने के बाद dभी न केवल एक प्रदर्शन मुद्दा है, यह आगे के कार्यान्वयन के मुद्दों की ओर जाता है क्योंकि सीमाओं के लिए आवश्यक "अनदेखी" पैटर्न को आगे के खाली पैटर्न पर प्रभाव डालने की अनुमति नहीं है ... एक गड़बड़!
फिलिप्पुस

@Philippos, उस 1d;1,2pस्क्रिप्ट में 1,2pकमांड पहली पंक्ति पर नहीं चलती है, इसलिए पहला पता किसी भी पैटर्न स्पेस से मेल नहीं खाता है , जो उस टेक्स्ट की व्याख्या करने का एक तरीका है। किसी भी स्थिति में, यह स्पष्ट होना चाहिए कि कमांड चलने के समय पतों का मूल्यांकन किया जाना चाहिए। जैसेsed 's/./x/g; /xxx/,/xxx/d'
स्टीफन चेज़लस

2
@ इस्साक, इस मुद्दे का मूल है। POSIX भाषा में 1और /1/दोनों पते हैं, 1वह पता है जब लाइन नंबर 1 है, /1/क्या पता है जब पैटर्न स्पेस होता है 1, तो सवाल यह है कि क्या दोनों प्रकार के पते को एक ही माना जाना चाहिए, या यदि लाइन नंबर रेंज पर विचार किया जाना चाहिए " पूर्ण में "चाहे वे मैच हो। अधिक ऐतिहासिक संदर्भ के लिए मेरा नवीनतम संपादन भी देखें।
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.