कैसे एक का उपयोग करने के लिए कई रिक्त स्थान पट्टी करने के लिए?


69

sedAIX पर वह नहीं हो रहा है जो मुझे लगता है कि इसे करना चाहिए। मैं IOSTAT के आउटपुट में एक ही स्थान के साथ कई स्थान बदलने का प्रयास कर रहा हूं:

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

#iostat|grep "hdisk1"|sed -e"s/[ ]*/ /g"
 h d i s k 1 0 . 1 6 . 3 0 . 5 6 3 3 4 5 8 8 0 1 1 2 4 3 2 3 5 4

sed को पूरे समूह (/ g) के लिए एक ही स्थान (/ /) के साथ कई रिक्त स्थान (/ [] * /) खोजना चाहिए और बदलना चाहिए ... लेकिन यह केवल ऐसा नहीं कर रहा है ... प्रत्येक वर्ण को स्थान देता है।

मैं क्या गलत कर रहा हूं? मुझे पता है कि यह कुछ सरल हो गया ... AIX 5300-06

संपादित करें: मेरे पास एक और कंप्यूटर है जिसमें 10+ हार्ड ड्राइव हैं। मैं इसे मॉनिटरिंग उद्देश्यों के लिए एक अन्य प्रोग्राम के पैरामीटर के रूप में उपयोग कर रहा हूं।

मैं जिस समस्या में भाग गया था, वह यह था कि "awk '{$ $ 5}' काम नहीं कर रहा था क्योंकि मैं द्वितीय चरण में $ 1 आदि का उपयोग कर रहा हूं और प्रिंट कमांड के साथ त्रुटियां दीं। मैं एक grep / sed / cut संस्करण की तलाश में था। क्या काम करने लगता है:

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

जब मैंने सोचा कि वे "सिर्फ एक" का मतलब "0 या अधिक" थे। कोष्ठक हटाने से यह काम कर गया। तीन बहुत अच्छे जवाब वास्तव में जल्दी से "उत्तर" चुनने के लिए कठिन बनाते हैं।

जवाबों:


52

का उपयोग grepबेमानी है, sedवही कर सकता है। समस्या *उस मैच के उपयोग में भी है जो 0 स्थान पर है, आपको \+इसके बजाय उपयोग करना होगा:

iostat | sed -n '/hdisk1/s/ \+/ /gp'

यदि आपका मेटाकार sedका समर्थन नहीं करता है \+, तो करें

iostat | sed -n '/hdisk1/s/  */ /gp'

AIX का समर्थन करने के लिए प्रतीत नहीं होता है, लेकिन हटाना [] की चाल है लगता है।
WernerCD

मैंने sed -n संस्करण का उपयोग करने की कोशिश की ... क्या होता है मेरे पास एक और कंप्यूटर है जिसमें 10+ ड्राइव हैं इसलिए यह 1, 10, 11, आदि करना शुरू कर देता है ... मैंने एक स्थान / hdisk1 / जोड़ने की कोशिश की और यह मुझे दिया एक "मान्यता प्राप्त कार्य नहीं"। क्या काम करने लगता है >> iostat | grep "hdisk1" | sed -e's / * / / g '
वर्नरसीडी

67

/[ ]*/शून्य या अधिक स्थानों से मेल खाता है , इसलिए वर्णों के बीच रिक्त स्ट्रिंग मेल खाती है।

यदि आप "एक या अधिक रिक्त स्थान" से मेल खाना चाह रहे हैं, तो इनमें से किसी एक का उपयोग करें:

... | sed 's/  */ /g'
... | sed 's/ \{1,\}/ /g'
... | tr -s ' '

आह ... [] इसे "वैकल्पिक" बनाता है। इससे स्पष्ट हुआ।
WernerCD

5
@WernerCD, कोई *इसे "वैकल्पिक" नहीं बनाता है। [ ]बस इसमें केवल एक वर्ण (एक स्थान) के साथ वर्णों की एक सूची बनाता है। यह क्वांटिफायर है, *जिसका अर्थ है "पिछली चीज़ का शून्य या अधिक"
ग्लेन जैकमैन

आह ... तो और अधिक सटीक होने के लिए, इसे एक सिंगल स्पेस / * / से बदलकर, डबल स्पेस के लिए किया जाता है। मैं गच्चा खा गया।
वर्नरसीडी

मैं एक ऐसे पैटर्न की खोज करने की कोशिश कर रहा था, जो केवल डबल स्पेस ही
खोजे

6
सबसे सरल tr -s ' 'समाधान के लिए +1
बेट्सन

12

अपने बदले *एक करने के लिए ऑपरेटर +। आप पिछले चरित्र के शून्य या अधिक मेल कर रहे हैं, जो हर वर्ण से मेल खाता है क्योंकि जो कुछ भी नहीं है वह स्थान है ... उम ... अंतरिक्ष के शून्य उदाहरण। आपको एक या अधिक मिलान करने की आवश्यकता है। वास्तव में दो या दो से अधिक मिलान करना बेहतर होगा

एक वर्ण से मेल खाने के लिए ब्रैकेटेड वर्ण वर्ग भी आवश्यक नहीं है। आप बस उपयोग कर सकते हैं:

s/  \+/ /g

... जब तक आप टैब या अन्य प्रकार के रिक्त स्थान से मेल खाना चाहते हैं, तब तक चरित्र वर्ग एक अच्छा विचार है।


AIX का समर्थन नहीं लगता है।
WernerCD

1
@WernerCD: फिर कोशिश करें s/ */ /g(कि तीन स्थानों के साथ, टिप्पणी स्वरूपण उन्हें ढह रहा है)। स्टार ऑपरेटर पिछले चरित्र को वैकल्पिक बना देगा, इसलिए यदि आप इसके साथ दो या दो से अधिक मिलान करते हैं तो आपको पहले दो स्वयं (दो रिक्त स्थान) का मिलान करने की आवश्यकता है, फिर तीसरे और निम्नलिखित स्थानों को वैकल्पिक बनाने के लिए एक तीसरा स्थान और एक सितारा जोड़ें।
कालेब

3
@userunknown: असल में मैं दो चीजों को एक साथ नहीं मिला रहा हूं, बाकी सब है :) एक सिंगल स्पेस को सिंगल स्पेस से रिप्लेस करना व्यर्थ है, आपको केवल उन मैचों पर यह एक्शन करने की जरूरत है जिनमें कम से कम दो अनुक्रमिक स्पेस हों। दो कंबल और एक प्लस या तीन ब्लैंक और एक स्टार बिल्कुल वही है जिसकी आवश्यकता है।
कालेब

@userunknown: यह इतनी बड़ी बात नहीं है कि यह थोड़ा सा प्रसंस्करण समय की बर्बादी है और यह मैच काउंटर जैसी चीजों को फेंक देता है।
कालेब

8

आप हमेशा किसी भी चीज़ के अनुक्रम में अंतिम घटना का मिलान कर सकते हैं:

s/\(sequence\)*/\1/

और इसलिए आप सही रास्ते पर हैं, लेकिन अनुक्रम को एक स्थान के साथ बदलने के बजाय - इसे अपनी अंतिम घटना के साथ बदलें - एक एकल स्थान। इस तरह यदि रिक्त स्थान का अनुक्रम मिलान किया जाता है, तो अनुक्रम एक ही स्थान पर कम हो जाता है, लेकिन यदि नल स्ट्रिंग का मिलान किया जाता है, तो नल स्ट्रिंग को स्वयं से बदल दिया जाता है - और कोई नुकसान नहीं, कोई बेईमानी नहीं। इसलिए, उदाहरण के लिए:

sed 's/\( \)*/\1/g' <<\IN                                    
# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

IN

आउटपुट

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty: tin tout avg-cpu: % user % sys % idle % iowait
 0.2 31.8 9.7 4.9 82.9 2.5

Disks: % tm_act Kbps tps Kb_read Kb_wrtn
hdisk9 0.2 54.2 1.1 1073456960 436765896
hdisk7 0.2 54.1 1.1 1070600212 435678280
hdisk8 0.0 0.0 0.0 0 0
hdisk6 0.0 0.0 0.0 0 0
hdisk1 0.1 6.3 0.5 63344916 112429672
hdisk0 0.1 5.0 0.2 40967838 98574444
cd0 0.0 0.0 0.0 0 0
hdiskpower1 0.2 108.3 2.3 2144057172 872444176

# iostat | grep hdisk1
hdisk1 0.1 6.3 0.5 63345700 112431123

सभी ने कहा, इस स्थिति में पूरी तरह से regexps से बचना शायद बेहतर है और इसके बजाय:

tr -s \  <infile

4
वास्तविक उत्तर की सरलता के लिए +1,iostat | tr -s \
वाइल्डकार्ड

'tr -s \' 'tr -s "" "के समान है। मुझे एहसास हुआ कि "\" के साथ भागकर स्ट्रिंग में एक तर्क के रूप में स्थान पारित किया जा सकता है। मैं देखता हूं कि इसका उपयोग शेल स्क्रिप्ट में भी किया जा सकता है। शांत अनुप्रयोग।
randominstanceOfLivingThing 16

5

ध्यान दें कि आप वह भी कर सकते हैं जो आप प्रयास करते हैं, वह है

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

द्वारा

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$re"; done

जो विशेष रूप से उपयोगी हो सकता है यदि आप बाद में अन्य क्षेत्रों तक पहुँचने और / या कुछ की गणना करने का प्रयास करते हैं - जैसे:

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$(( re/1024 )) Mb"; done

बहुत अच्छा। पहला संस्करण काम करता है। मेरे AIX बॉक्स दूसरे को पसंद नहीं करते। सभी तीन बॉक्स आउटपुट: "$ [पुनः / 1024] एमबी"। मेरे द्वारा उपयोग किए जा रहे निगरानी उपकरण में रिपोर्ट के लिए रूपांतरण हैं, इसलिए यह मेरे लिए "आवश्यक" चीज नहीं है, लेकिन मुझे यह पसंद है।
वर्नरसीडी

@enzotib को सही करने के लिए धन्यवाद while
रोज़ज़ेट्राइजेविज़

@WernerCD आह, यह $[ .. ]संभवतः हाल के संस्करणों में उपलब्ध है (शायद zsh भी)। मैंने उत्तर को अधिक पोर्टेबल के $(( .. ))बजाय अद्यतन किया ।
रोज़ज़ेट्राइजेविज़

यही चाल चली। मुझे यह देखना पड़ेगा। आकर्षक लगा।
WernerCD

0

आप एक ही स्थान, एक टैब या किसी अन्य स्ट्रिंग के लिए कई स्थानों को परिवर्तित करने के लिए निम्न स्क्रिप्ट का उपयोग कर सकते हैं:

$ ls | compress_spaces.sh       # converts multiple spaces to one
$ ls | compress_spaces.sh TAB   # converts multiple spaces to a single tab character
$ ls | compress_spaces.sh TEST  # converts multiple spaces to the phrase TEST
$ compress_spaces.sh help       # show the help for this command

compress_spaces.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: {REPLACE_WITH}

  NOTE: If you pass in TAB, then multiple spaces are replaced with a TAB character

  no args -> multiple spaces replaced with a single space
  TAB     -> multiple spaces replaced with a single tab character
  TEST    -> multiple spaces replaced with the phrase "TEST"

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show help if we're not getting data from stdin
if [ -t 0 ]; then
  show_help
fi

REPLACE_WITH=${1:-' '}

if [ "$REPLACE_WITH" == "tab" ]
then
  REPLACE_WITH=$'\t'
fi
if [ "$REPLACE_WITH" == "TAB" ]
then
  REPLACE_WITH=$'\t'
fi

sed "s/ \{1,\}/$REPLACE_WITH/gp"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.