`कॉलम -t` जैसे कमांड जो आउटपुट में विभाजक रखता है


17

मैं एक साधारण तालिका संपादित कर रहा हूं। मैं इसे अच्छी तरह से स्वरूपित करना चाहूंगा। मैं इस्तेमाल कर सकते हैं जबकि tbl, latex, या इसी तरह, इस overkill लगता है - सादा पाठ वास्तव में पर्याप्त है। जैसा कि यह सरल है मैं स्रोत के रूप में अच्छी तरह से उत्पादन हो सकता है। तो स्रोत भी अच्छा दिखना चाहिए। ऐसा लगता है कि यह एक सही काम होना चाहिए column -s '|' -t- यह विभाजक पाता है और प्रत्येक कॉलम में अधिकतम चौड़ाई के अनुसार संरेखित करने के लिए स्वचालित रूप से रिक्त स्थान सम्मिलित करता है। दुर्भाग्य से, यह विभाजकों को हटा देता है, इसलिए मैं आगे संपादन के बाद इसे फिर से नहीं कर सकता। क्या कोई अच्छा टेक्स्ट-प्रोसेसिंग टूल है जो इस आदर्श को कर सकता है, ताकि यह आउटपुट इनपुट के रूप में कार्य करे? या क्या मुझे अपना लिखने की आवश्यकता है?

संपादित करें: यहाँ एक उदाहरण है जो मुझे चाहिए:

foo |   bar | baz
abc def | 12 | 23456

बन जाना चाहिए

foo     | bar | baz
abc def | 12  | 3456

जब ' 'विभाजक और स्पेसर दोनों column -tअच्छी तरह से काम करता है। लेकिन मेरी वस्तुओं में जगह है, इसलिए मैं उसका उपयोग नहीं कर सकता। स्पेसर्स अलग होने से अलग चीजों को जटिल करता है। मुझे लगता है कि विभाजकों के बगल में उन्हें विभाजक पात्रों के रूप में माना जाना उपयोगी है, लेकिन ऐसा नहीं column -s '|' -tहै (हालांकि वर्तमान व्यवहार भी उपयोगी है)।


आप emacs org- मोड का उपयोग कर सकते हैं। तालिका का समर्थन वास्तव में काफी अद्भुत है, कार्यक्षमता की तरह स्प्रेडशीट प्रदान करता है।
vschum

सामान्य रूप से नहीं जैसा कि मैंने सोचा था कि यह उचित होगा, लेकिन विशेष रूप से leancrew.com/all-this/2008/08/tables-for-markdown-and-textmate पर मार्कड टेबल के लिए एक अजगर कार्यक्रम है ।
wanoise

यह एक ऐसी समस्या है जिसे मैं कम से कम हर दो सप्ताह में चलाता हूं। printfहर बार होलोकॉस्ट को बायपास करने का एकमात्र व्यवहार्य समाधान , जो मैंने अब तक पाया है, @डेटा में एक अद्वितीय चार (जैसे ) जोड़ रहा है , और ... | column -s@ -tबाद में उपयोग करें ।
साजास

जवाबों:


17

यकीन नहीं होता अगर मैं सही समझ गया कि आपकी समस्या क्या है। लेकिन, क्या इसे एक अतिरिक्त अस्थायी विभाजक जोड़कर हल किया जा सकता है? इसलिए आप विभाजकों को चिह्नित करने के लिए दूसरे विभाजक का उपयोग कर सकते हैं, मूल विभाजक को अछूता रखते हुए।

इस उदाहरण को देखें जहां मैं "" को प्रत्येक "" में जोड़ता हूं। इसलिए कॉलम कमांड का इनपुट "xxx @ | yyyy" होगा। कॉलम "@" को "रखते हुए" प्रोसेस करेगा। अछूता:

~$ echo "foo | this is some text | bar" | sed 's/|/@|/g'  | column -s '@' -t
foo   | this is some text   | bar

चतुर। लगभग वही करता है जो मैं चाहता हूं, और वास्तव में वही करता है जो मैंने पूछा था - विभाजकों को अंदर छोड़ता है। मैं यह भी चाहता हूं कि सच्चे विभाजकों के बगल में रिक्त स्थान को समायोजित किया जा सके, बल्कि केवल यहां के रूप में।
9

@wnoise: sed 's/ *| */@| /g'इसके बजाय का उपयोग करें
स्टीफन जिमेनेज

@ स्टीफन जिमेनेज़: और फिक्स के sed 's/ |/|/g'बाद columnअतिरिक्त रिक्त स्थान जोड़े जाने से। अब हमारे पास एक समाधान है जो मेरे लिए काफी अच्छा काम करता है। (हालांकि यह अच्छा होगा यदि यह इस तरह के एक अतिरिक्त चरित्र पर निर्भर नहीं करता है। यदि कोई उपलब्ध नहीं है तो क्या होगा?)
wanoise

3
@wnoise: @ के बजाय, आप कुछ ऐसी चीज़ों का उपयोग कर सकते हैं जो आम तौर पर पाठ में दिखाई नहीं देती हैं, जैसे कि कम ASCII मूल्य, जैसे। $ '\ x01' ... (लेकिन $ '\ x00' नहीं ...)
पीटर।

6

यह तब उपलब्ध नहीं था जब आपने प्रश्न पूछा था लेकिन v। 2.23 column से util-linuxआप आउटपुट विभाजक का चयन कर सकते हैं

   -o, --output-separator string
          Specify the columns delimiter for table output (default is two spaces).

तो बस चलाएं:

 column -s '|' -o '|' -t infile

ध्यान दें कि util-linuxलेखन के समय संस्करण उबंटू 18.04 (और शायद अन्य देबैन व्युत्पन्न डिस्ट्रोस) पर उपलब्ध नहीं है। केवल bsdmainutilsसंस्करण उपलब्ध है। bsdmainutilsसंस्करण उत्पादन स्वरूपण का समर्थन नहीं करता।
htaccess

5

यहाँ एक बैश स्क्रिप्ट है। यह 'कॉलम -t` का उपयोग नहीं करता है, और सेपरेटर को ठीक उसी तरह से नियंत्रित किया जाता है, जैसा कि IFS है, क्योंकि यह IFS (या कम से कम, IFS के awk का आंतरिक संस्करण) है ... डिफ़ॉल्ट सीमांकक $' t 't है

यह स्क्रिप्ट पूरी तरह से सबसे सही फ़ील्ड को निकालती है।
'कॉलम' ऐसा नहीं करता है।
सभी कॉलमों को पैडिंग करके, इस स्क्रिप्ट को
टेबल फ्रेम बनाने के लिए आसानी से संशोधित किया जा सकता है ।

ध्यान दें। इनपुट फ़ाइल को दो बार संसाधित करने की आवश्यकता है
('कॉलम' को भी ऐसा करने की आवश्यकता होगी)
पहला पास कॉलम अधिकतम चौड़ाई प्राप्त करना है।
दूसरा पास फ़ील्ड (प्रति स्तंभ) का विस्तार करने के लिए है

कुछ विकल्प जोड़े और एक चमकता हुआ बग (नामकरण चर :(

  • -एल लेफ्ट ट्रिम व्हाट्सएप के किसी भी इंडेंटेड फील्ड
  • -r सही ट्रिम व्हाट्सएप व्यापक पाठ की तुलना में व्यापक (स्तंभ के लिए)
  • -b दोनों -l और -r
  • -L वाम आउटपुट सीमांकक जोड़ा जाता है
  • -R सही आउटपुट सीमांकक जोड़ा जाता है
  • -बी दोनों -L और -R
  • -S आउटपुट सेपरेटर चुनें

#!/bin/bash
#
#   script [-F sep] [file]
#
#   If file is not specified, stdin is read 
#    
# ARGS ######################################################################
l=;r=;L=;R=;O=;F=' ' # defaults
for ((i=1;i<=${#@};i++)) ;do
  case "$1" in
    -- ) shift 1;((i--));break ;;
    -l ) l="-l";shift 1;((i-=1)) ;;        #  left strip whitespace
    -r ) r="-r";shift 1;((i-=1)) ;;        # right strip whitespace
    -b ) l="-l";r="-r";shift 1;((i-=1)) ;; # strip  both -l and -r whitespace
    -L ) L="-L";shift 1;((i-=1)) ;;        #  Left output delimiter is added
    -R ) R="-R";shift 1;((i-=1)) ;;        # Right output delimiter is added
    -B ) L="-L";R="-R";shift 1;((i-=1)) ;; # output Both -L and -R delimiters
    -F ) F="$2";shift 2;((i-=2)) ;; # source separator
    -O ) O="$2";shift 2;((i-=2)) ;; # output  separator. Default = 1st char of -F 
    -* ) echo "ERROR: invalid option: $1" 1>&2; exit 1 ;;
     * ) break ;;
  esac
done
#
if  [[ -z "$1" ]] ;then # no filename, so read stdin
  f="$(mktemp)"
  ifs="$IFS"; IFS=$'\n'; set -f # Disable pathname expansion (globbing)
  while read -r line; do
    printf "%s\n" "$line" >>"$f"
  done
  IFS="$ifs"; set +f # re-enable pathname expansion (globbing)
else
  f="$1"
fi
[[ -f "$f" ]] || { echo "ERROR: Input file NOT found:" ;echo "$f" ;exit 2 ; }
[[ -z "$F" ]] && F=' '        # input Field Separator string
[[ -z "$O" ]] && O="$F"       # output Field Separator
                 O="${O:0:1}" #   use  single char only

# MAIN ######################################################################
max="$( # get max length of each field/column, and output them
  awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" '
    BEGIN { if (F!="") FS=F }
    { for (i=1;i<=NF;i++) { 
        if (l=="-l") { sub("^[ \t]*","",$i) }
        if (r=="-r") { sub("[ \t]*$","",$i) }
        len=length($i); if (len>max[i]) { max[i]=len } 
        if (i>imax) { imax=i } 
      } 
    }
    END { for(i=1;i<=imax;i++) { printf("%s ",max[i]) } }
  ' "$f" 
)"

awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" -v_max="$max" '
  BEGIN { if (F!="") FS=F; cols=split(_max,max," ") }
  { # Bring each field up to max len and output with delimiter
    printf("%s",L=="-L"?O:"")
    for(i=1;i<=cols;i++) { if (l=="-l") { sub("^[ \t]*","",$i) } 
                           if (r=="-r") { sub("[ \t]*$","",$i) }
      printf("%s%"(max[i]-length($i))"s%s",$i,"",i==cols?"":O) 
    } 
    printf("%s\n",R=="-R"?O:"")
  }
' "$f"

# END #######################################################################    
if  [[ -z "$1" ]] ;then # no filename, so stdin was used
  rm "$f"   # delete temp file
fi
exit

अच्छी तरह से किया। बेशक, मैं ऐसी चीज की उम्मीद कर रहा था जिसे वास्तव में एक नया कार्यक्रम लिखने की आवश्यकता नहीं होगी।
9


1

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

  1. रिक्त स्थान से घिरे एकल गैर-अल्फ़ान्यूमेरिक वर्णों के लिए पार्स इनपुट, उन्हें सॉर्ट करें, जो सबसे आम है, और मान लें कि सबसे आम चरित्र सीमांकक है, जिसे सौंपा गया है $d
  2. Hmonoliu के उत्तर में कम या ज्यादा आगे बढ़ें , लेकिन ASCII NULL का उपयोग पैडिंग के रूप में करें, इसके बजाय a@ पीटरो की टिप्पणी के अनुसार, ।

कोड एक फ़ंक्शन है जो फ़ाइल नाम, या किसी अन्य इनपुट से स्वीकार करता है STDIN :

algn() { 
    d="$(grep -ow '[^[:alnum:]]' "${1:-/dev/stdin}"  | \
         sort | uniq -c | sort -rn | sed -n '1s/.*\(.$\)/\1/p')" ;
    sed "s/ *$d */\x01$d /g" "${1:-/dev/stdin}"  | column -s $'\001' -t ;
}

आउटपुट algn foo(या भी algn < foo):

foo      | bar  | baz
abc def  | 12   | 23456

एक साल बाद इसे देखते हुए, ऐसा लगता है कि STDIN मंगलाचरण नहीं कर सकता है और इसे काम नहीं करना चाहिए क्योंकि यह दो बार STDIN का उपयोग करता है । बड़ी फ़ाइलों (लगभग 80 मिलियन लाइनों) के साथ परीक्षण यह इंगित करता है कि यह स्पष्ट रूप से सही ढंग से काम करता है। हम्म ...
एजीसी

0

सरल आदेश को लागू करने के लिए हामनतोली का विचार :

#! /bin/bash
delim="${1:-,}"
interm="${2:-\~}"
sed "s/$delim/$interm$delim/g" | column -t -s "$interm" | sed "s/  $delim/$delim/g"

टिप्पणी:

  • ${1:-,} - के साथ एक पहला तर्क है , डिफ़ॉल्ट के रूप में
  • पहले sedएक मध्यवर्ती प्रतीक सम्मिलित करता है ($interm 2 तर्क या ~डिफ़ॉल्ट रूप से)
  • फिर column इंटरमीडिएट सिंबल को उन जगहों से बदल देता है जो संरेखण करते हैं
  • दूसरा sedबेमानी जगहों को साफ करता हैcolumn कमांड के

उपयोग उदाहरण:

$ echo "
a: bb: cccc
aaaa: b : cc
" | align :

a   : bb: cccc
aaaa: b : cc

इसमें यह भी अच्छा है कि यह आदर्श है: आप इसे कई बार लागू कर सकते हैं और एक ही परिणाम प्राप्त कर सकते हैं (उदाहरण के लिए जब आप vim और realign में संपादित करते हैं)।

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