सॉर्ट करें लेकिन शीर्ष लेख को शीर्ष पर रखें


55

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


1
मैं निम्नलिखित लिंक पर आया । हालाँकि, मुझे { head -1; sort; }काम करने की यह तकनीक नहीं मिल रही है । यह हमेशा पहली पंक्ति के बाद पाठ का एक गुच्छा हटाता है। क्या किसी को पता है यह क्यों होता है?
जॉन्ड्री

1
मुझे संदेह है कि यह headएक बफर में एक से अधिक लाइन पढ़ रहा है और इसे दूर फेंक रहा है। मेरे sedविचार में भी यही समस्या थी।
एंडी

@ जॉन्डर्री - यह तकनीक केवल lseekसक्षम इनपुट के साथ काम करती है इसलिए पाइप से पढ़ते समय यह काम नहीं करेगी। यह काम करेगा यदि आप किसी फ़ाइल पर रीडायरेक्ट करते हैं >outfileऔर फिर रन करते हैं{ head -n 1; sort; } <outfile
don_crissti

जवाबों:


58

एंडी के विचार को चोरी करना और इसे एक फ़ंक्शन बनाना ताकि इसका उपयोग करना आसान हो:

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

अब मैं कर सकता हूँ:

$ ps -o pid,comm | body sort -k2
  PID COMMAND
24759 bash
31276 bash
31032 less
31177 less
31020 man
31167 man
...

$ ps -o pid,comm | body grep less
  PID COMMAND
31032 less
31177 less

ps -C COMMANDसे अधिक उपयुक्त हो सकता है grep COMMAND, लेकिन यह सिर्फ एक उदाहरण है। इसके अलावा, आप उपयोग नहीं कर सकते हैं -Cयदि आप एक और चयन विकल्प का उपयोग करते हैं जैसे कि -U
मिकेल

या शायद इसे बुलाया जाना चाहिए body? में के रूप में body sortया body grep। विचार?
मिकेल

3
से नाम रखा गया headerहै body, क्योंकि आप शरीर पर कार्रवाई कर रहे हैं। उम्मीद है कि अधिक समझ में आता है।
मिकेल

2
bodyसभी बाद के पाइपलाइन प्रतिभागियों को कॉल करने के लिए याद रखें :ps -o pid,comm | body grep less | body sort -k1nr
बिशप

1
@ समय आप लिख सकते हैं <foo body sort -k2या body sort -k2 <foo। आप जो चाहते थे, उससे सिर्फ एक अतिरिक्त चरित्र।
मिकेल

36

आप शीर्ष को बैश के साथ इस तरह शीर्ष पर रख सकते हैं:

command | (read -r; printf "%s\n" "$REPLY"; sort)

या इसे पर्ल के साथ करें:

command | perl -e 'print scalar (<>); print sort { ... } <>'

2
+1 का कमाल। मुझे लगता है कि एक शेल फ़ंक्शन के रूप में वर्थ बंडलिंग।
मिकेल

1
+1, किसी भी कारण से एक उपखंड बेहतर है, या {}इसके बजाय ठीक है ()?
jonderry

2
IFS=इनपुट को पढ़ते समय शब्द विभाजन को निष्क्रिय करता है। मुझे नहीं लगता कि पढ़ते समय यह आवश्यक है $REPLYechoयदि xpg_echoसेट किया गया है (डिफ़ॉल्ट नहीं) तो बैकस्लैश एस्केप का विस्तार करेगा ; printfउस मामले में अधिक सुरक्षित है। echo $REPLYउद्धरण के बिना व्हॉट्सएप संघनित हो जाएगा; मुझे लगता है कि echo "$REPLY"ठीक होना चाहिए। read -rयदि इनपुट में बैकस्लैश एस्केप हो सकता है तो इसकी आवश्यकता है। इसमें से कुछ बैश संस्करण पर निर्भर हो सकता है।
एंडी

1
@Andy: वाह, आप सही कह रहे हैं, अलग-अलग नियमों के लिए read REPLY; echo $REPLY(स्ट्रिप्स प्रमुख स्थान) और read; echo $REPLY(नहीं)।
मिकेल

1
@Andy: IIRC, xpg_echoआपके सिस्टम पर निर्भर होने का डिफ़ॉल्ट मान , जैसे Solaris पर मुझे लगता है कि यह सत्य के लिए चूक है। यही कारण है कि गाइल्स को printfबहुत पसंद है: यह केवल पूर्वानुमानित व्यवहार के साथ ही बात है।
मिकेल

23

मुझे एक अच्छा awk संस्करण मिला जो स्क्रिप्ट में अच्छी तरह से काम करता है:

awk 'NR == 1; NR > 1 {print $0 | "sort -n"}'

1
मुझे यह पसंद है, लेकिन इसके लिए थोड़ा स्पष्टीकरण की आवश्यकता है - पाइप awk स्क्रिप्ट के अंदर है। वह कैसे काम करता है? क्या यह sortकमांड को बाहरी रूप से बुला रहा है ? क्या किसी को कम से कम एक पेज के लिंक के बारे में पता है जो जाग के भीतर पाइप का उपयोग करता है?
वाइल्डकार्ड

@Wildcard आप आधिकारिक मैनुअल पेज या इस प्राइमर की जांच कर सकते हैं ।
19

4

हैकिश लेकिन प्रभावी: छँटाई से पहले 0सभी हेडर लाइनों और 1अन्य सभी लाइनों के लिए प्रस्तुत करना। छँटाई के बाद पहला पात्र पट्टी करें।

… |
awk '{print (NR <= 2 ? "0 " : "1 ") $0}' |
sort -k 1 -k… |
cut -b 3-

3

यहाँ कुछ जादू पर्ल लाइन शोर है कि आप सब कुछ सॉर्ट करने के लिए अपने आउटपुट को पाइप कर सकते हैं लेकिन पहली पंक्ति को सबसे ऊपर रखें: perl -e 'print scalar <>, sort <>;'


2

मैंने command | {head -1; sort; }समाधान की कोशिश की और यह पुष्टि कर सकता है कि यह वास्तव में चीजों को खराब कर देता है - headपाइप से कई लाइनों में पढ़ता है, फिर बस पहले एक को आउटपुट करता है। इसलिए शेष आउटपुट, जो पढ़ा head नहीं गया थाsort - को लाइन 2 से शुरू होने वाले बाकी आउटपुट से पास किया गया है!

परिणाम यह है कि आप लापता लाइनें (और एक आंशिक रेखा!) जो आपके कमांड आउटपुट की शुरुआत में थीं (सिवाय आपके अभी भी पहली पंक्ति है) - एक तथ्य जो wcअंत में एक पाइप जोड़कर पुष्टि करना आसान है उपरोक्त पाइपलाइन - लेकिन यह पता लगाने के लिए असाधारण रूप से मुश्किल है कि क्या आपको यह पता नहीं है! मैंने इसे हल करने से पहले अपने आउटपुट में एक आंशिक लाइन (पहले 100 बाइट्स या कट ऑफ) क्यों था, यह जानने के लिए कम से कम 20 मिनट बिताए।

मैंने जो काम किया, जो खूबसूरती से काम किया और दो बार कमांड चलाने की आवश्यकता नहीं थी, वह था:

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile
sed 1d $myfile | sort

rm $myfile

यदि आपको आउटपुट को फ़ाइल में डालने की आवश्यकता है, तो आप इसे इसमें संशोधित कर सकते हैं:

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile > outputfile
sed 1d $myfile | sort >> outputfile

rm $myfile

आप ksh93 की headअंतर्निहित या lineउपयोगिता का उपयोग कर सकते हैं (सिस्टम पर जो अभी भी एक है) या gnu-sed -u qया IFS=read -r line; printf '%s\n' "$line", जो उस से बचने के लिए एक समय में इनपुट एक बाइट को पढ़ता है।
स्टीफन चेज़लस

1

मुझे लगता है कि यह सबसे आसान है।

ps -ef | ( head -n 1 ; sort )

या यह जो संभवतः तेज है क्योंकि यह उप शेल नहीं बनाता है

ps -ef | { head -n 1 ; sort ; }

अन्य शांत उपयोग करता है

शीर्ष लेख पंक्ति के बाद फेरबदल करें

cat file.txt |  ( head -n 1 ; shuf )

शीर्ष लेख पंक्ति के बाद रिवर्स लाइनें

cat file.txt |  ( head -n 1 ; tac )

2
Unix.stackexchange.com/questions/11856/… देखें । यह वास्तव में एक अच्छा समाधान नहीं है।
वाइल्डकार्ड

1
काम नहीं कर रहे हैं, cat file | { head -n 1 ; sort ; } > file2केवल सिर दिखाते हैं
पीटर क्रूस

0
command | head -1; command | tail -n +2 | sort

4
यह commandदो बार शुरू होता है। इसलिए यह कुछ विशिष्ट आदेशों तक सीमित है। हालाँकि, psउदाहरण में अनुरोधित आदेश के लिए, यह काम करेगा।
जोफेल

0

सरल और सीधा!

<command> | head -n 1; <command> | sed 1d | sort <....>
  • sed nd ---> 'n' लाइन नंबर निर्दिष्ट करता है, और 'd' डिलीट के लिए खड़ा है।

1
जिस तरह सर्व के जवाब पर डेढ़ साल पहले जोफेल ने टिप्पणी की थी, यह commandदो बार शुरू होता है । तो वास्तव में एक पाइपलाइन में उपयोग के लिए उपयुक्त नहीं है।
वाइल्डकार्ड

0

मैं यहां आज्ञा का हल ढूंढने आया था w। यह कमांड इस बात का विवरण दिखाता है कि कौन लॉग इन है और क्या कर रहा है।

क्रमबद्ध परिणाम दिखाने के लिए, लेकिन शीर्ष पर रखे गए शीर्षकों के साथ (शीर्ष लेखों की 2 पंक्तियाँ हैं), मैं इस पर आ गया:

w | head -n 2; w | tail -n +3 | sort

जाहिर है कि यह wदो बार कमान चलाता है और इसलिए सभी स्थितियों के लिए उपयुक्त नहीं हो सकता है। हालांकि, इसके लाभ के लिए यह याद रखना काफी आसान है।

ध्यान दें कि tail -n +3साधन 'तीसरी तरफ से सभी लाइनें दिखाएं' ( man tailविवरण के लिए देखें)।


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