নাম দিয়ে নির্দিষ্ট কলাম কীভাবে প্রিন্ট করা যায়?


32

আমার কাছে নিম্নলিখিত ফাইল রয়েছে:

id  name  age
1   ed    50
2   joe   70   

আমি শুধু idএবং ageকলামগুলি মুদ্রণ করতে চাই । এই মুহূর্তে আমি কেবল ব্যবহার awk:

cat file.tsv | awk '{ print $1, $3 }'

তবে এর জন্য কলামের সংখ্যাগুলি জানতে হবে। এটি করার কি কোনও উপায় আছে যেখানে আমি কলামের নামের পরিবর্তে কলামের নামটি ব্যবহার করতে পারি (প্রথম সারিতে উল্লিখিত)?


7
catবিটিডাব্লু প্রয়োজন হয় না। আপনি ব্যবহার করতে পারেনawk '{ print $1, $3 }' file.tsv
— এরিক উইলসন

না হলে কলাম নম্বর , তারপর কি আপনার উপর নির্ভর করে করতে চান?
— rozcietrzewiacz

2
@Zrocietrzewiacz নাম; তিনি idপরিবর্তে $1এবং ageপরিবর্তে বলতে চান$3
— মাইকেল মরোজেক

আরো দেখুন আলোচনা Stackoverflow
— Hotschke

উত্তর:


37

এরকম কিছু হতে পারে:

$ cat t.awk
NR==1 {
    for (i=1; i<=NF; i++) {
        ix[$i] = i
    }
}
NR>1 {
    print $ix[c1], $ix[c2]
}
$ awk -f t.awk c1=id c2=name input 
1 ed
2 joe
$ awk -f t.awk c1=age c2=name input 
50 ed
70 joe

আপনি যদি কমান্ড লাইনে মুদ্রণ করতে কলামগুলি নির্দিষ্ট করতে চান তবে আপনি এই জাতীয় কিছু করতে পারেন:

$ cat t.awk 
BEGIN {
    split(cols,out,",")
}
NR==1 {
    for (i=1; i<=NF; i++)
        ix[$i] = i
}
NR>1 {
    for (i in out)
        printf "%s%s", $ix[out[i]], OFS
    print ""
}
$ awk -f t.awk -v cols=name,age,id,name,id input 
ed 1 ed 50 1 
joe 2 joe 70 2 

( ব্লকে -vপরিবর্তনশীল সংজ্ঞায়িত করতে স্যুইচটি নোট করুন BEGIN))


আমি শিথিল করণ শিথিল করলাম ... পরিবর্তনশীল সংখ্যক কলামকে সমর্থন করার সর্বোত্তম উপায় কোনটি? awk -f t.awk col1 col2 ... coln inputআদর্শ হবে; awk -f t.awk cols=col1,col2,...,coln inputখুব কার্যকর হবে
— ব্রেট থমাস

1
আমার উত্তর আপডেট। আপনি যদি এটি দিয়ে স্টাফ করতে চান তবে এটি শেখা বন্ধ করুন :)
— মাদুর

3
দ্বিতীয় উদাহরণটি প্রত্যাশিত ক্রমে কলামগুলি আউটপুট দেয় না, for (i in out)এর অন্তর্নিহিত ক্রম নেই। একটি সমাধান হিসাবে gawkপ্রস্তাব PROCINFO["sorted_in"], একটি সঙ্গে সূচক উপর পুনরাবৃত্তি for( ; ; )সম্ভবত আরও ভাল।
— মিঃ স্পুর্যাটিক

@ ব্রেটথোমাস, এই টিউটোরিয়ালটির অত্যন্ত পরামর্শ দিন । (যদি আপনার লিন্ডা ডটকম অ্যাক্সেস থাকে তবে আমি আরও উচ্চতর "আওক এসেনশিয়াল ট্রেনিং," এর প্রস্তাব দিচ্ছি যা একই উপাদানগুলিকে আরও সংক্ষিপ্তভাবে এবং অনুশীলন অনুশীলনের সাথে কভার করে।)
— ওয়াইল্ডকার্ড

মিঃ স্পুর্যাটিক, আপনি দা মানুষ। আমি (আমি বাইরে) সমস্যার জন্য দৌড়েছি, ডাব্লু / ৩ টি ক্ষেত্রের জন্য কাজ করেছি, যখন আমি 2 যুক্ত করেছি তখন এটি আমার পছন্দ মতো 1,2,3,4,5 এর পরিবর্তে 4,5,1,2,3 করেছিল । সেগুলিকে পেতে যাতে করতে হয় (i = 1; i <= দৈর্ঘ্য (আউট); i ++)
— সেভেরুন

5

কেবল পার্ল সমাধানটি লটে নেওয়া হচ্ছে:

#!/usr/bin/perl -wnla

BEGIN {
    @f = ('id', 'age');   # field names to print
    print "@f";           # print field names
}

if ($. == 1) {            # if line number 1
    @n = @F;              #   get all field names
} else {                  # or else
    @v{@n} = @F;          #   map field names to values
    print "@v{@f}";       #   print values based on names
}

5

csvkit

একটি CSV বিন্যাসে ইনপুট ডেটা রূপান্তর করুন এবং যেমন একটি CSV সরঞ্জামটি ব্যবহার csvcutথেকে csvkit:

$ cat test-cols.dat 
id  name  age
1   ed    50
2   joe   70 

সিএসভিকিট ইনস্টল করুন:

$ pip install csvkit

এটিকে একটি বৈধ সিএসভি ফাইলে রূপান্তর করতে এবং প্রয়োগ করার জন্য এর স্কুইজ trবিকল্পটি ব্যবহার করুন :-scsvcut

$ cat test-cols.dat | tr -s ' ' ',' | csvcut -c id,age
id,age
1,50
2,70

আপনি যদি পুরানো ডেটা ফর্ম্যাটে ফিরে আসতে চান তবে আপনি ব্যবহার করতে পারেন tr ',' ' ' | column -t

$ cat test-cols.dat | tr -s ' ' ',' | csvcut -c id,age | tr ',' ' ' | column -t
id  age
1   50
2   70

নোট

  • সিএসভিকিট বিভিন্ন ডিলিমিটারকে ( শেয়ারড অপশন -d বা --delimiter) সমর্থন করে তবে একটি সিএসভি ফাইল দেয়:

    • ফাইলটি কলামগুলি পৃথক করতে কেবল ফাঁকা জায়গা ব্যবহার করে (কোনও ট্যাব নেই), নিম্নলিখিত কাজ করে

      $ csvcut -d ' ' -S -c 'id,age' test-cols.dat
      id,age
      1,50
      2,70
    • ফাইলটি যদি কলামগুলি পৃথক করতে একটি ট্যাব ব্যবহার করে, নিম্নলিখিতটি কাজ করে এবং csvformatটিএসভি ফাইল ফিরে পেতে ব্যবহার করা যেতে পারে:

      $ csvcut -t -c 'id,age' test-cols.dat | csvformat -T
      id  age
      1   50
      2   70

      আমি যতদূর যাচাই করেছি কেবলমাত্র একটিমাত্র ট্যাব অনুমোদিত।

  • csvlook একটি চিহ্ন ডাউন টেবিল বিন্যাসে টেবিল ফর্ম্যাট করতে পারেন

    $ csvcut -t -c "id,age" test-cols.dat | csvlook
    | id | age |
    | -- | --- |
    |  1 |  50 |
    |  2 |  70 |
  • ইউইউওসি (বিড়ালের অপ্রয়োজনীয় ব্যবহার) : কমান্ডটি তৈরি করতে আমার এটি পছন্দ হয়।


+1 টি। তবে এর অপ্রয়োজনীয় trব্যবহারও। টিএসভি ফাইলগুলি সিএসভিতে রূপান্তর করার কোনও প্রয়োজন ছাড়াই সরাসরি সমর্থিত। -t(ওরফে --tabs) বিকল্প বলে cvscutক্ষেত্র বিভেদক হিসাবে ট্যাব ব্যবহার করতে। এবং -dবা --delimiterডিলিমিটার হিসাবে কোনও চরিত্র ব্যবহার করতে।
— ক্যাস

কিছু পরীক্ষার সাথে, এটি মনে হয় -dএবং -tবিকল্পগুলি আধা-ভাঙা। তারা ইনপুট ডিলিমিটার নির্দিষ্ট করার জন্য কাজ করে তবে আউটপুট ডিলিমিটারটি সর্বদা কমা হতে হার্ডকড থাকে। আইএমওটি নষ্ট হয়ে গেছে - এটি হয় ইনপুট ডিলিমিটারের সমান হতে পারে বা ব্যবহারকারীর awk'এফএস' এবং 'অফস' ভার্সনের মতো আউটপুট ডিলিমিটার সেট করার অনুমতি দেওয়ার জন্য অন্য বিকল্প থাকতে পারে ।
— ক্যাস

4

আপনি যদি কেবলমাত্র ক্ষেত্রগুলিকে সংখ্যার পরিবর্তে তাদের নাম দিয়ে উল্লেখ করতে চান তবে আপনি ব্যবহার করতে পারেন read:

while read id name age
do
  echo "$id $age"
done < file.tsv 

সম্পাদনা

আমি আপনার অর্থ শেষ পর্যন্ত দেখেছি! এখানে একটি বাশ ফাংশন রয়েছে যা কেবলমাত্র কমান্ড লাইনে ( নাম অনুসারে ) নির্দিষ্ট করা কলামগুলি মুদ্রণ করবে ।

printColumns () 
{ 
read names
while read $names; do
    for col in $*
    do
        eval "printf '%s ' \$$col"
    done
    echo
done
}

আপনার উপস্থাপন করা ফাইলটির সাথে আপনি এটি কীভাবে ব্যবহার করতে পারেন তা এখানে:

$ < file.tsv printColumns id name
1 ed 
2 joe 

(ফাংশনটি পড়ছে stdin। < file.tsv printColumns ... এর সমতুল্য printColumns ... < file.tsvএবং cat file.tsv | printColumns ...)

$ < file.tsv printColumns name age
ed 50 
joe 70 

$ < file.tsv printColumns name age id name name name
ed 50 1 ed ed ed 
joe 70 2 joe joe joe

দ্রষ্টব্য: আপনার অনুরোধ করা কলামগুলির নামগুলিতে মনোযোগ দিন! এই সংস্করণে স্যানিটি চেক নেই, তাই যুক্তিগুলির মধ্যে একটির মতো কিছু হলে খারাপ কাজগুলি ঘটতে পারে"anything; rm /my/precious/file"


1
এর জন্য কলামের সংখ্যাগুলিও জানতে হবে। শুধু কারণ আপনি তাদের নাম id, nameএবং age, আসলে, যাতে আপনার হার্ড কোডেড হয় পরিবর্তন করে না readলাইন।
— janmoesen

1
@ জঞ্জোমেন হ্যাঁ, অবশেষে আমি পয়েন্টটি পেয়েছি :)
— রোজিট্রিজেভিয়াচজ

এটি দুর্দান্ত, ধন্যবাদ। আমি বড় ফাইলগুলি (1000 কলাম, কয়েক মিলিয়ন সারি) নিয়ে কাজ করছি তাই গতির জন্য অ্যাড ব্যবহার করছি।
— ব্রেট থমাস

পছন্দ করুন আমি তখন খুব কৌতূহলী: আপনি কি কিছু মানদণ্ড পোস্ট করতে পারেন যা সময়ের তুলনা দেয়? (ব্যবহার time { command(s); })
— rozcietrzewiacz

@ ক্রোসিত্রেইয়েজ:time cat temp.txt | ./col1 CHR POS > /dev/null 99.144u 38.966s 2:19.27 99.1% 0+0k 0+0io 0pf+0w time awk -f col2 c1=CHR c2=POS temp.txt > /dev/null 0.294u 0.127s 0:00.50 82.0% 0+0k 0+0io 0pf+0w
— ব্রেট থমাস

3

এর মূল্য কী। এটি উত্সের যে কোনও সংখ্যক কলাম এবং মুদ্রণের জন্য যে কোনও সংখ্যক কলাম হ্যান্ডল করতে পারে, আপনি যে কোনও আউটপুট ক্রম চয়ন করেন; শুধু আরোগুলি পুনরায় ব্যবস্থা ...

যেমন। কল:script-name id age

outseq=($@)
colnum=($( 
  for ((i; i<${#outseq[@]}; i++)) ;do 
    head -n 1 file |
     sed -r 's/ +/\n/g' |
      sed -nr "/^${outseq[$i]}$/="
  done ))
tr ' ' '\t' <<<"${outseq[@]}"
sed -nr '1!{s/ +/\t/gp}' file |
  cut -f $(tr ' ' ','<<<"${colnum[@]}") 

আউটপুট

id      age
1       50
2       70

2

আপনি যে ফাইলটি পড়ছেন তা যদি কখনও ব্যবহারকারীর দ্বারা উত্পাদিত না হতে পারে তবে আপনি পঠিত বিল্টিনটিকে অপব্যবহার করতে পারেন:

f=file.tsv
read $(head -n1 "$f") extra <<<`seq 100`
awk "{print \$$id, \$$age}" "$f"

ইনপুট ফাইলের সম্পূর্ণ প্রথম লাইনটি আর্গুমেন্ট তালিকায় পরিবর্তিত হয়, তাই readশিরোনাম লাইন থেকে সমস্ত ক্ষেত্রের নাম ভেরিয়েবলের নাম হিসাবে পাস করা হয়। এর মধ্যে প্রথমটি 1 প্রদান করে যা seq 100উত্পন্ন করে, দ্বিতীয়টি 2 পায়, তৃতীয়টি 3 পায় এবং আরও। seqডামি ভেরিয়েবল দ্বারা অতিরিক্ত আউটপুট ভিজিয়ে রাখা হয় extra। আপনি যদি আগে সময়ের ইনপুট কলামগুলির সংখ্যা জানেন তবে 100 টি মিলিয়ে পরিবর্তন করতে পারবেন এবং এ থেকে মুক্তি পেতে পারেন extra।

awkস্ক্রিপ্ট ডাবল উদ্ধৃত স্ট্রিং, শেল ভেরিয়েবল দ্বারা সংজ্ঞায়িত যার ফলে হয় readযেমন স্ক্রিপ্ট মধ্যে প্রতিস্থাপিত করা awkক্ষেত্র সংখ্যা।


1

সাধারণত ফাইল শিরোনামটি দেখতে, আপনার প্রয়োজনীয় কলামটির সংখ্যা গণনা ( সি ) এবং তারপরে ইউনিক্স ব্যবহার করা সহজ হয় cut:

cut -f c -d, file.csv

কিন্তু যখন অনেকগুলি কলাম বা অনেকগুলি ফাইল থাকে আমি নীচের কুরুচিপূর্ণ কৌশলটি ব্যবহার করি:

cut \
  -f $(head -1 file.csv | sed 's/,/\'$'\n/g' | grep -n 'column name' | cut -f1 -d,) \
  -d, \ 
  file.csv

file.csvওএসএক্সে পরীক্ষিত, এটি কমা-সীমাবদ্ধ।


1

একটি একক কলাম নির্বাচন করার জন্য এখানে একটি দ্রুত উপায়।

বলুন আমরা "foo" নামক কলামটি চাই:

f=file.csv; colnum=`head -1 ${f} | sed 's/,/\n/g' | nl | grep 'foo$' | cut -f 1 `; cut -d, -f ${colnum} ${f}

মূলত, শিরোনামের লাইনটি নিন, প্রতি লাইনে এক কলামের নাম দিয়ে একাধিক লাইনে বিভক্ত করুন, রেখাগুলির সংখ্যা দিন, পছন্দসই নামের সাথে রেখাটি নির্বাচন করুন এবং যুক্ত লাইন নম্বরটি পুনরুদ্ধার করুন; তারপরে কাটা কমান্ডের কলাম নম্বর হিসাবে লাইন নম্বরটি ব্যবহার করুন।


0

একটি অনুরূপ সমাধান খুঁজছেন (আমার আইডি নামের কলামটি প্রয়োজন, যার একটি পৃথক কলাম নম্বর থাকতে পারে), আমি এইটি দেখতে পেলাম:

head -n 1 file.csv | awk -F',' ' {
      for(i=1;i < NF;i++) {
         if($i ~ /id/) { print i }
      }
} '

0

আমি এই উদ্দেশ্যে একটি পাইথন স্ক্রিপ্ট লিখেছিলাম যা মূলত এটির মতো কাজ করে:

with fileinput.input(args.file) as data:
    headers = data.readline().split()
    selectors = [any(string in header for string in args.fixed_strings) or
                 any(re.search(pat, header) for pat in args.python_regexp)
                 for header in headers]

    print(*itertools.compress(headers, selectors))
    for line in data:
        print(*itertools.compress(line.split(), selectors))

আমি এটিকে হেডার গ্রেপেরhgrep জন্য ডেকেছি , এটি এটির মতো ব্যবহার করা যেতে পারে:

$ hgrep data.txt -F foo bar -P ^baz$
$ hgrep -F foo bar -P ^baz$ -- data.txt
$ grep -v spam data.txt | hgrep -F foo bar -P ^baz$

পুরো স্ক্রিপ্টটি কিছুটা দীর্ঘ, কারণ এটি argparseকমান্ড লাইনের যুক্তিগুলি পার্স করতে ব্যবহার করে এবং কোডটি নিম্নরূপ:

#!/usr/bin/python3

import argparse
import fileinput
import itertools
import re
import sys
import textwrap


def underline(s):
    return '\033[4m{}\033[0m'.format(s)


parser = argparse.ArgumentParser(
    usage='%(prog)s [OPTIONS] {} [FILE]'.format(
        underline('column-specification')),
    description=
        'Print selected columns by specifying patterns to match the headers.',
    epilog=textwrap.dedent('''\
    examples:
      $ %(prog)s data.txt -F foo bar -P ^baz$
      $ %(prog)s -F foo bar -P ^baz$ -- data.txt
      $ grep -v spam data.txt | %(prog)s -F foo bar -P ^baz$
    '''),
    formatter_class=argparse.RawTextHelpFormatter,
)

parser.add_argument(
    '-d', '--debug', action='store_true', help='include debugging information')
parser.add_argument(
    'file', metavar='FILE', nargs='?', default='-',
    help="use %(metavar)s as input, default is '-' for standard input")
spec = parser.add_argument_group(
    'column specification', 'one of these or both must be provided:')
spec.add_argument(
    '-F', '--fixed-strings', metavar='STRING', nargs='*', default=[],
    help='show columns containing %(metavar)s in header\n\n')
spec.add_argument(
    '-P', '--python-regexp', metavar='PATTERN', nargs='*', default=[],
    help='show a column if its header matches any %(metavar)s')

args = parser.parse_args()

if args.debug:
    for k, v in sorted(vars(args).items()):
        print('{}: debug: {:>15}: {}'.format(parser.prog, k, v),
              file=sys.stderr)

if not args.fixed_strings and not args.python_regexp:
    parser.error('no column specifications given')


try:
    with fileinput.input(args.file) as data:
        headers = data.readline().split()
        selectors = [any(string in header for string in args.fixed_strings) or
                     any(re.search(pat, header) for pat in args.python_regexp)
                     for header in headers]

        print(*itertools.compress(headers, selectors))
        for line in data:
            print(*itertools.compress(line.split(), selectors))

except BrokenPipeError:
    sys.exit(1)
except KeyboardInterrupt:
    print()
    sys.exit(1)

0

awk, সমস্ত মদ জন্য, সহজাতভাবে পূর্ণসংখ্যার সূচকযুক্ত হয় cut।

নাম-সূচকযুক্ত ডেটা হ্যান্ডেল করার জন্য এখানে বেশ কয়েকটি সরঞ্জাম প্রস্তুত করা হয়েছে (তাদের বেশিরভাগ কেবল CSV এবং টিএসভি পরিচালনা করে যা খুব জনপ্রিয় ফাইল ফর্ম্যাটগুলি):


0

নির্দিষ্ট শিরোনামগুলি কাটাতে এই ছোট অ্যাঙ্ক ইউটিলিটিটি ব্যবহার করে দেখুন - https://github.com/rohitprajapati/toyeca-cutter

ব্যবহারের উদাহরণ -

awk -f toyeca-cutter.awk -v c="col1, col2, col3, col4" my_file.csv
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.