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


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.