বাশে কোনও ফাইল স্থানান্তর করার একটি কার্যকর উপায়


110

আমার মতো বিশাল আকারের ট্যাব-বিভক্ত ফাইল রয়েছে

X column1 column2 column3
row1 0 1 2
row2 3 4 5
row3 6 7 8
row4 9 10 11

আমি কেবলমাত্র বাশ কমান্ড ব্যবহার করে এটি দক্ষ পদ্ধতিতে স্থানান্তর করতে চাই (এটি করার জন্য আমি দশ বা তাই লাইন পার্ল স্ক্রিপ্ট লিখতে পারি, তবে দেশীয় বাশ ফাংশনগুলির চেয়ে এটি কার্যকর করতে ধীর হওয়া উচিত)। সুতরাং আউটপুট মত দেখতে হবে

X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11

আমি এরকম একটি সমাধানের কথা ভেবেছিলাম

cols=`head -n 1 input | wc -w`
for (( i=1; i <= $cols; i++))
do cut -f $i input | tr $'\n' $'\t' | sed -e "s/\t$/\n/g" >> output
done

তবে এটি ধীর এবং সবচেয়ে কার্যকর সমাধান বলে মনে হচ্ছে না। আমি এই পোস্টে vi এর জন্য একটি সমাধান দেখেছি , তবে এটি এখনও ধীর গতিতে। কোন চিন্তা / পরামর্শ / উজ্জ্বল ধারণা? :-)


12
আপনি কী ভাবছেন যে এখানে কোনও বাশ স্ক্রিপ্ট থাকবে যা পার্ল স্ক্রিপ্টের চেয়ে দ্রুত হতে চলেছে? পার্লের মধ্যে ঠিক এই ধরণের সমস্যাটিই ছাড়িয়ে গেছে
মার্ক পিম

1
@ চিহ্ন, যদি এটি বিশুদ্ধ বাশ হয় তবে এটি সমস্ত কাটা / সেড ইত্যাদি সরঞ্জামগুলিকে এক সাথে জড়িত করার চেয়ে দ্রুততর হতে পারে। তবে আবার, আপনি যদি সংশ্লেষের সরঞ্জামগুলির মতো "বাশ "টিকে সংজ্ঞায়িত করেন তবে কেবল একটি awk স্ক্রিপ্ট লেখা পার্ল আর্ট টেক্সট প্রসেসিংয়ের সাথে তুলনীয় হবে।
ghostdog74

পার্লটি এখানে কীভাবে ধীর হবে তা বুঝতে না পারার জন্য অন্যটিকে যুক্ত করুন। কোড লিখতে আস্তে? কার্যকর করতে ধীর? আমি পার্লকে সত্যই অপছন্দ করি, তবে এটি এই ধরণের টাস্কে এক্সেল করে।
কোরি পোর্টার

যদি আপনার কলাম / ক্ষেত্রগুলির একটি নির্দিষ্ট আকার / প্রস্থ থাকে, তবে আপনি মেমরিতে আপনার ফাইলটি পড়া এড়াতে পাইথন ফাইলটি ব্যবহার করতে পারেন। আপনার কি স্থির কলাম / ক্ষেত্রের আকার / প্রস্থ রয়েছে?
tommy.carstensen

2
যে কেউ মনে করেন যে শেল স্ক্রিপ্টটি awk বা পার্লের চেয়ে দ্রুততর হবে ইউনিক্স.স্ট্যাকেক্সেঞ্জাওয়েজ / প্রশ্নগুলি / ১69৯69১16১/২ পড়তে হবে তাই তারা কেন বুঝতে পারে তা কেন তা নয়।
এড মর্টন

উত্তর:


114
awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}' file

আউটপুট

$ more file
0 1 2
3 4 5
6 7 8
9 10 11

$ ./shell.sh
0 3 6 9
1 4 7 10
2 5 8 11

জোনাথন 10000 লাইনের ফাইলে পার্ল সমাধানের বিপরীতে অভিনয়

$ head -5 file
1 0 1 2
2 3 4 5
3 6 7 8
4 9 10 11
1 0 1 2

$  wc -l < file
10000

$ time perl test.pl file >/dev/null

real    0m0.480s
user    0m0.442s
sys     0m0.026s

$ time awk -f test.awk file >/dev/null

real    0m0.382s
user    0m0.367s
sys     0m0.011s

$ time perl test.pl file >/dev/null

real    0m0.481s
user    0m0.431s
sys     0m0.022s

$ time awk -f test.awk file >/dev/null

real    0m0.390s
user    0m0.370s
sys     0m0.010s

এড মর্টন দ্বারা সম্পাদিত সম্পাদনা (আপনি যদি অস্বীকার করেন তবে @ ghostdog74 নির্দ্বিধায় মুক্ত হন)।

সম্ভবত আরও কিছু স্পষ্ট পরিবর্তনশীল নাম সহ এই সংস্করণটি নীচের কয়েকটি প্রশ্নের উত্তর দিতে এবং স্ক্রিপ্টটি কী করছে তা সাধারণত পরিষ্কার করতে সহায়তা করবে। এটি পৃথককারী হিসাবে ট্যাবগুলিও ব্যবহার করে যা ওপি মূলত অনুরোধ করেছিল যাতে এটি খালি ক্ষেত্রগুলি পরিচালনা করতে পারে এবং এটি কাকতালীয়ভাবে বিশেষ ক্ষেত্রে এই বিশেষ ক্ষেত্রে আউটপুটটি সামান্যই আপ করতে পারে।

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{
    for (rowNr=1;rowNr<=NF;rowNr++) {
        cell[rowNr,NR] = $rowNr
    }
    maxRows = (NF > maxRows ? NF : maxRows)
    maxCols = NR
}
END {
    for (rowNr=1;rowNr<=maxRows;rowNr++) {
        for (colNr=1;colNr<=maxCols;colNr++) {
            printf "%s%s", cell[rowNr,colNr], (colNr < maxCols ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk file
X       row1    row2    row3    row4
column1 0       3       6       9
column2 1       4       7       10
column3 2       5       8       11

উপরের সমাধানগুলি যে কোনও বেকায়দায় কাজ করবে (পুরানো, ভাঙা অ্যাজক অবশ্যই - সেখানে ওয়াইএমএমভি)।

উপরের সমাধানগুলি পুরো ফাইলটিকে মেমোরিতে পড়তে পারে - যদি ইনপুট ফাইলগুলি এর জন্য খুব বেশি হয় তবে আপনি এটি করতে পারেন:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ printf "%s%s", (FNR>1 ? OFS : ""), $ARGIND }
ENDFILE {
    print ""
    if (ARGIND < NF) {
        ARGV[ARGC] = FILENAME
        ARGC++
    }
}
$ awk -f tst.awk file
X       row1    row2    row3    row4
column1 0       3       6       9
column2 1       4       7       10
column3 2       5       8       11

যা প্রায় কোনও মেমরি ব্যবহার করে না তবে একটি লাইনে প্রতি ক্ষেত্রের সংখ্যায় একবার ইনপুট ফাইলটি পড়ে তাই এটি পুরো ফাইলটিকে মেমরিতে পড়ায় এমন সংস্করণটির চেয়ে অনেক ধীর হবে। এটি প্রতিটি লাইনে ক্ষেত্রের সংখ্যা একই বলে ধরে নিয়েছে এবং এটি জিএনইউ অ্যাডকে ব্যবহার করে ENDFILEএবং ARGINDতবে যে কোনও উত্তেজক পরীক্ষা FNR==1এবং পরীক্ষা দিয়ে একই কাজ করতে পারে END


এবং এখন সারি এবং কলাম লেবেলগুলিও পরিচালনা করতে চান?
জোনাথন লেফলার

ঠিক আছে - আপনি সঠিক; আপনার নমুনা তথ্য প্রশ্নের নমুনা ডেটার সাথে মেলে না, তবে আপনার কোড প্রশ্নের নমুনা ডেটার উপর সূক্ষ্মভাবে কাজ করে এবং প্রয়োজনীয় আউটপুট দেয় (ফাঁকা বনাম ট্যাব স্পেসিং দিন বা নিন)। মূলত আমার ভুল।
জোনাথন লেফলার

আকর্ষণীয় সময় - আমি সম্মতি জানাতে পারি যে আপনি বেকায়দায় একটি পারফরম্যান্স বেনিফিট দেখেন। আমি ম্যাকস এক্স 10.5.8 ব্যবহার করছিলাম যা 'গাওক' ব্যবহার করে না; এবং আমি পার্ল ব্যবহার করছিলাম 5.10.1 (32-বিট বিল্ড)। আমি সংগ্রহ করি যে আপনার ডেটা প্রতি লাইন 4 কলাম সহ 10000 লাইন ছিল? যাইহোক, এটি কোনও বড় ব্যাপার নয়; দু'একটি পার্ক এবং পার্লই কার্যকর সমাধান (এবং এডাব্লিক সমাধানটি আরও নিকৃষ্ট - আমার পার্লের 'সংজ্ঞায়িত' চেকগুলি কঠোর / সতর্কতার অধীনে ফ্রি রানের সতর্কতার জন্য প্রয়োজনীয়) এবং না কোনও ঝালাই এবং উভয়ই সম্ভবত আসলটির চেয়ে দ্রুত গতিযুক্ত হওয়ার সম্ভাবনা রয়েছে শেল স্ক্রিপ্ট সমাধান।
জোনাথন লেফলার

আমার আসল ২.২ জিবি ম্যাট্রিক্সে পার্ল দ্রষ্টব্যটি অ্যাজকের তুলনায় কিছুটা দ্রুত - 350.103 এস বনাম 369.410 সে আমি পার্ল ব্যবহার করছিলাম 5.8.8 64 বিট
ফেডেরিকো

1
@ zx8754 যে সর্বাধিক সংখ্যক ক্ষেত্র কেবলমাত্র একটি পুরানো, নন-পসিক অজকের ক্ষেত্রে প্রযোজ্য। সম্ভবত অবিশ্বাস্যভাবে দুর্ভাগ্যক্রমে নাম "নাক" named এটি গাওক বা অন্যান্য আধুনিক জাতির জন্য প্রযোজ্য নয়।
এড মর্টন

47

অন্য বিকল্পটি হ'ল rs:

rs -c' ' -C' ' -T

-cইনপুট কলাম বিভাজক -Cপরিবর্তন করে, আউটপুট কলাম বিভাজক পরিবর্তন করে এবং -Tসারি এবং কলামগুলি স্থানান্তর করে। -tপরিবর্তে ব্যবহার করবেন না -T, কারণ এটি স্বয়ংক্রিয়ভাবে গণনা করা সারি এবং কলামগুলির সংখ্যা ব্যবহার করে যা সাধারণত সঠিক নয়। rsযা এপিএলে পুনরায় আকার ফাংশনের নামে নামকরণ করা হয়েছে, এটি BSD এবং OS X এর সাথে আসে তবে এটি অন্যান্য প্ল্যাটফর্মের প্যাকেজ পরিচালকদের কাছ থেকে পাওয়া উচিত।

দ্বিতীয় বিকল্পটি হ'ল রুবি ব্যবহার করা:

ruby -e'puts readlines.map(&:split).transpose.map{|x|x*" "}'

তৃতীয় বিকল্পটি হ'ল jq:

jq -R .|jq -sr 'map(./" ")|transpose|map(join(" "))[]'

jq -R .প্রতিটি ইনপুট লাইনটিকে JSON স্ট্রিং আক্ষরিক হিসাবে মুদ্রণ করে, -s( --slurp) প্রতিটি লাইনকে JSON হিসাবে পার্স করার পরে ইনপুট লাইনগুলির জন্য একটি অ্যারে তৈরি করে এবং -r( --raw-output) JSON স্ট্রিং লিটারেলের পরিবর্তে স্ট্রিংয়ের বিষয়বস্তু আউটপুট দেয়। /অপারেটর বিভক্ত স্ট্রিং ওভারলোড করা হয়।


3
আমি এর সাথে পরিচিত ছিলাম না rs- পয়েন্টারের জন্য ধন্যবাদ! (লিঙ্কটি ডেবিয়ানের; প্রবাহটি মিরবাসড.আর.আই.আর.ও.এস.
ডিস্ট

2
@ ল্লেবার্ড কমপক্ষে বাস্তবায়নের ক্ষেত্রে rsএটি ওএস এক্সের সাথে আসে, -cএকা একা ট্যাবে ইনপুট কলাম বিভাজক সেট করে।
নিসেটামা

2
@ লেলেবার্দে, একটি ট্যাব চরিত্র পেতে বাশের এএনএসআই-সি উদ্ধৃতি দিয়ে চেষ্টা করুন :$'\t'
গ্লেন জ্যাকম্যান

3
এটি একটি চূড়ান্ত কেস, তবে একটি অনেক বড় ফাইলের জন্য অনেকগুলি সারি যেমন TTC TTA TTC TTC TTTচলমান rs -c' ' -C' ' -T < rows.seq > cols.seqদেয় rs: no memory: Cannot allocate memory। এটি 32 জিবি র‌্যাম সহ ফ্রিবিএসডি 11.0-রিলেস চালিত একটি সিস্টেম। সুতরাং, আমার অনুমান যে rsসমস্ত কিছু র‍্যামে রাখে যা গতির পক্ষে ভাল তবে বড় ডেটার জন্য নয়।
9:30

1
jq একটি 766MB ফাইলে 21Gb র‌্যাম ব্যবহার করেছে। আমি 40 মিনিটের পরে কোনও আউটপুট ছাড়াই এটি হত্যা করেছি।
গ্লুবড্রব্বব

30

একটি পাইথন সমাধান:

python -c "import sys; print('\n'.join(' '.join(c) for c in zip(*(l.split() for l in sys.stdin.readlines() if l.strip()))))" < input > output

উপরোক্ত নিম্নলিখিতগুলির উপর ভিত্তি করে:

import sys

for c in zip(*(l.split() for l in sys.stdin.readlines() if l.strip())):
    print(' '.join(c))

এই কোডটি ধরে নিয়েছে যে প্রতিটি লাইনে একই সংখ্যক কলাম রয়েছে (কোনও প্যাডিং হয় না)।


3
এখানে এক ছোটখাট সমস্যা: প্রতিস্থাপন l.split()দ্বারা l.strip().split()(পাইথন 2.7), আর আউটপুট শেষ লাইনটি খোঁড়া। যথেচ্ছ কলাম বিভাজকগুলির জন্য কাজ করে, ব্যবহার করুন l.strip().split(sep)এবং sep.join(c)আপনার বিভাজকটি যদি চলকতে সঞ্চিত থাকে sep
krlmlr

21

TRANSPOSE SourceForge উপর প্রকল্পের ঠিক যে জন্য একটি coreutil মত সি প্রোগ্রাম।

gcc transpose.c -o transpose
./transpose -t input > output #works with stdin, too.

লিঙ্কের জন্য ধন্যবাদ। তবে বড় ম্যাট্রিক্স / ফাইলগুলির সাথে ডিল করার সময় এটির জন্য খুব বেশি স্মৃতি দরকার।
tommy.carstensen

এটা blocksize এবং fieldsize জন্য আর্গুমেন্ট রয়েছে: tweaking চেষ্টা -bএবং -fআর্গুমেন্ট।
উড়ন্ত ভেড়া

ডিফল্ট ব্লকের আকার (- block or -b) 10kb এবং ডিফল্ট ক্ষেত্রের আকার (--ফিল্ডম্যাক্স বা -f) is৪, তাই এটি এটি হতে পারে না। আমি চেষ্টা করেছিলাম. যদিও পরামর্শ জন্য ধন্যবাদ।
tommy.carstensen

1
2 জিবি সাইজের সিএসভি দিয়ে ভাল কাজ করেছে।
শৃঙ্খলা

2
মোটামুটি 11k 5k দ্বারা মাত্রা সহ একটি ম্যাট্রিক্স ফাইলের জন্য, আমি ট্রান্সপোজ.কে 7x দ্রুত এবং গস্টডোগ .৪ এর প্রথম অ্যাজক সমাধানের চেয়ে মেমরি-দক্ষ ~ 5x হিসাবে বেশি পেয়েছি। এছাড়াও, আমি দেখতে পেলাম যে ঘোস্টডোগ aw৪ এর "কোডটি প্রায় কোনও স্মৃতি ব্যবহার করে না" সঠিকভাবে কাজ করে না। এছাড়াও, ট্রান্সপোজ.সি প্রোগ্রামে - লিমিট ফ্ল্যাগের জন্য নজর রাখুন, যা ডিফল্টরূপে আউটপুটকে 1 কে দ্বারা মাত্রা 1 কে সীমাবদ্ধ করে।
ncemami

16

খাঁটি বেস, কোনও অতিরিক্ত প্রক্রিয়া। একটি দুর্দান্ত অনুশীলন:

declare -a array=( )                      # we build a 1-D-array

read -a line < "$1"                       # read the headline

COLS=${#line[@]}                          # save number of columns

index=0
while read -a line ; do
    for (( COUNTER=0; COUNTER<${#line[@]}; COUNTER++ )); do
        array[$index]=${line[$COUNTER]}
        ((index++))
    done
done < "$1"

for (( ROW = 0; ROW < COLS; ROW++ )); do
  for (( COUNTER = ROW; COUNTER < ${#array[@]}; COUNTER += COLS )); do
    printf "%s\t" ${array[$COUNTER]}
  done
  printf "\n" 
done

এটি আমার ফাইলটির জন্য কাজ করেছে, যদিও এটি আকর্ষণীয়ভাবে এটি সারণীর প্রথম লাইনের জন্য একটি ডিরেক্টরি তালিকা প্রিন্ট করে। আমি জানার জন্য পর্যাপ্ত BASH জানি না।
বাগগাফ

@ বুগ্লোফ আপনার টেবিলের কোণে একটি * রয়েছে।
হ্যালো 71

2
@ বুগ্লোফ: সঠিকভাবে ভেরিয়েবল উদ্ধৃত করা এড়ানো উচিত:printf "%s\t" "${array[$COUNTER]}"
পরবর্তী বিজ্ঞপ্তি না হওয়া পর্যন্ত

16

কটাক্ষপাত আছে গনুহ datamash যা মত ব্যবহার করা যেতে পারে datamash transpose। ভবিষ্যতের সংস্করণ ক্রস ট্যাবুলেশনকে সমর্থন করবে (পিভট টেবিলগুলি)


9

কাজটি করার জন্য এখানে একটি পরিমিতরূপে শক্ত পার্ল স্ক্রিপ্ট। @ ঘোস্টডোগ's৪ এর awkসমাধান সহ অনেক কাঠামোগত উপমা রয়েছে ।

#!/bin/perl -w
#
# SO 1729824

use strict;

my(%data);          # main storage
my($maxcol) = 0;
my($rownum) = 0;
while (<>)
{
    my(@row) = split /\s+/;
    my($colnum) = 0;
    foreach my $val (@row)
    {
        $data{$rownum}{$colnum++} = $val;
    }
    $rownum++;
    $maxcol = $colnum if $colnum > $maxcol;
}

my $maxrow = $rownum;
for (my $col = 0; $col < $maxcol; $col++)
{
    for (my $row = 0; $row < $maxrow; $row++)
    {
        printf "%s%s", ($row == 0) ? "" : "\t",
                defined $data{$row}{$col} ? $data{$row}{$col} : "";
    }
    print "\n";
}

নমুনা ডেটার আকারের সাথে পার্ল এবং অ্যাজকের পারফরম্যান্সের পার্থক্য নগণ্য (মোট 7 টির মধ্যে 1 মিলিসেকেন্ড)। বৃহত্তর ডেটা সেট (100x100 ম্যাট্রিক্স, প্রতিটি 6-8 টি অক্ষর প্রবেশ করে) দিয়ে, পারল কিছুটা আউটপোরফর্মড অ্যাজ - 0.026 বনাম 0.042 এস s উভয়ই সমস্যা হওয়ার সম্ভাবনা নেই।


পার্ল ৫.১০.১ (৩২-বিট) বনাম অ্যাওডও (সংস্করণ ২০০৪০২০77 যখন '-ভি' দেওয়া হয়) বনাম গ্যাক ৩.১..7 (৩২-বিট) ম্যাকোস এক্স ১০.৫.৮ (৩২-বিট) প্রতি ১০ টি কলাম সহ ১০,০০০ লাইনের ফাইল রয়েছে লাইন:

Osiris JL: time gawk -f tr.awk xxx  > /dev/null

real    0m0.367s
user    0m0.279s
sys 0m0.085s
Osiris JL: time perl -f transpose.pl xxx > /dev/null

real    0m0.138s
user    0m0.128s
sys 0m0.008s
Osiris JL: time awk -f tr.awk xxx  > /dev/null

real    0m1.891s
user    0m0.924s
sys 0m0.961s
Osiris-2 JL: 

নোট করুন যে গাওক এই মেশিনে অ্যাজকের চেয়ে অনেক দ্রুত, তবে পার্লের চেয়ে ধীর। স্পষ্টতই, আপনার মাইলেজটি পৃথক হবে।


আমার সিস্টেমে, গ্যালাক আউটফর্মফর্ম পার্ল। আপনি আমার সম্পাদিত পোস্টে আমার ফলাফলগুলি দেখতে পাচ্ছেন
ghostdog74

4
উপসংহারটি সংগ্রহ করা হয়েছে: বিভিন্ন প্ল্যাটফর্ম, বিভিন্ন সফ্টওয়্যার সংস্করণ, বিভিন্ন ফলাফল।
ghostdog74

6

আপনি যদি scইনস্টল করে থাকেন তবে আপনি এটি করতে পারেন:

psc -r < inputfile | sc -W% - > outputfile

4
নোট করুন যে এটি সীমিত সংখ্যক লাইনের সমর্থন করে কারণ scএর কলামগুলিকে এক বা দুটি অক্ষরের সংমিশ্রণ হিসাবে নাম দেয়। সীমা হ'ল 26 + 26^2 = 702
থোর

6

এর জন্য একটি উদ্দেশ্য নির্মিত ইউটিলিটি রয়েছে,

জিএনইউ দাতাম্যাশ ইউটিলিটি

apt install datamash  

datamash transpose < yourfile

এই সাইট থেকে নেওয়া, https://www.gnu.org/software/datamash/ এবং http://www.tilersuxrain.com/articles/transposing-rows- এবং- কলামগুলি ৩-- অর্থসূত্র


5

আপনার সমস্ত সারিতে একই সংখ্যক ক্ষেত্র রয়েছে বলে ধরে নেওয়া, এই অভীক প্রোগ্রামটি সমস্যার সমাধান করে:

{for (f=1;f<=NF;f++) col[f] = col[f]":"$f} END {for (f=1;f<=NF;f++) print col[f]}

কথায় কথায়, আপনি সারিগুলি লুপ করার সাথে সাথে প্রতিটি ক্ষেত্রের জন্য f':' - পৃথক স্ট্রিংটি col[f]সেই ক্ষেত্রের উপাদানগুলি যুক্ত করে grow সমস্ত সারিটি সম্পন্ন করার পরে, এই স্ট্রিংগুলির প্রতিটি একটি পৃথক লাইনে মুদ্রণ করুন। তারপরে আউটপুটটি পাইপ করে আপনি যে বিভাজকটি চান তার জন্য ':' প্রতিস্থাপন করতে পারেন (বলুন, একটি স্থান)tr ':' ' '

উদাহরণ:

$ echo "1 2 3\n4 5 6"
1 2 3
4 5 6

$ echo "1 2 3\n4 5 6" | awk '{for (f=1;f<=NF;f++) col[f] = col[f]":"$f} END {for (f=1;f<=NF;f++) print col[f]}' | tr ':' ' '
 1 4
 2 5
 3 6


3

একটি হ্যাকিশ পারল সমাধান এর মতো হতে পারে। এটি দুর্দান্ত কারণ এটি সমস্ত ফাইল মেমোরিতে লোড করে না, মধ্যবর্তী টেম্প ফাইলগুলি মুদ্রণ করে এবং তারপরে অদ্ভূত পেস্ট ব্যবহার করে

#!/usr/bin/perl
use warnings;
use strict;

my $counter;
open INPUT, "<$ARGV[0]" or die ("Unable to open input file!");
while (my $line = <INPUT>) {
    chomp $line;
    my @array = split ("\t",$line);
    open OUTPUT, ">temp$." or die ("unable to open output file!");
    print OUTPUT join ("\n",@array);
    close OUTPUT;
    $counter=$.;
}
close INPUT;

# paste files together
my $execute = "paste ";
foreach (1..$counter) {
    $execute.="temp$counter ";
}
$execute.="> $ARGV[1]";
system $execute;

পেস্ট এবং টেম্প ফাইলগুলি ব্যবহার করা কেবলমাত্র অতিরিক্ত অপ্রয়োজনীয় ক্রিয়াকলাপ। আপনি কেবল মেমরির ভিতরে নিজেই
হেরফের

2
হ্যাঁ, তবে তার মানে কি সব কিছু স্মৃতিতে রাখা নয়? আমি যে ফাইলগুলি নিয়ে কাজ করছি তার আকার প্রায় 2-20gb।
ফেডেরিকো জর্জি

3

আপনার নিজের উদাহরণে আমি দেখতে পাচ্ছি কেবল উন্নতিই কর্ক ব্যবহার করা যা চলমান প্রক্রিয়াগুলির সংখ্যা এবং তাদের মধ্যে যে পাইপযুক্ত ডেটার পরিমাণ হ্রাস করবে:

/bin/rm output 2> /dev/null

cols=`head -n 1 input | wc -w` 
for (( i=1; i <= $cols; i++))
do
  awk '{printf ("%s%s", tab, $'$i'); tab="\t"} END {print ""}' input
done >> output

3

আমি সাধারণত awkএই প্রয়োজনের জন্য এই ছোট স্নিপেটটি ব্যবহার করি :

  awk '{for (i=1; i<=NF; i++) a[i,NR]=$i
        max=(max<NF?NF:max)}
        END {for (i=1; i<=max; i++)
              {for (j=1; j<=NR; j++) 
                  printf "%s%s", a[i,j], (j==NR?RS:FS)
              }
        }' file

এটি কেবলমাত্র সমস্ত ডেটা একটি দ্বিদিকের অ্যারেতে লোড করে a[line,column]এবং তারপরে এটি আবার মুদ্রণ করেa[column,line] , যাতে এটি প্রদত্ত ইনপুট স্থানান্তর করে।

maxএটিতে প্রাথমিক ফাইলের ইমাম পরিমাণের কলামের নজর রাখা দরকার , যাতে এটি মুদ্রণের জন্য সারিগুলির সংখ্যা হিসাবে ব্যবহৃত হয়।


2

আমি fgm এর সমাধান (ধন্যবাদ fgm!) ব্যবহার করেছি, তবে প্রতিটি সারিটির শেষে ট্যাব অক্ষরগুলি অপসারণ করা দরকার, সুতরাং স্ক্রিপ্টটি এভাবে পরিবর্তন করুন:

#!/bin/bash 
declare -a array=( )                      # we build a 1-D-array

read -a line < "$1"                       # read the headline

COLS=${#line[@]}                          # save number of columns

index=0
while read -a line; do
    for (( COUNTER=0; COUNTER<${#line[@]}; COUNTER++ )); do
        array[$index]=${line[$COUNTER]}
        ((index++))
    done
done < "$1"

for (( ROW = 0; ROW < COLS; ROW++ )); do
  for (( COUNTER = ROW; COUNTER < ${#array[@]}; COUNTER += COLS )); do
    printf "%s" ${array[$COUNTER]}
    if [ $COUNTER -lt $(( ${#array[@]} - $COLS )) ]
    then
        printf "\t"
    fi
  done
  printf "\n" 
done

2

আমি ঠিক অনুরূপ বাশ ট্র্যানপোজ খুঁজছিলাম কিন্তু প্যাডিংয়ের জন্য সমর্থন সহ। এফজিএম এর সমাধানের ভিত্তিতে আমি যে স্ক্রিপ্টটি লিখেছি তা এখানে কার্যকর হয়েছে বলে মনে হচ্ছে। যদি এটি সাহায্য করতে পারে ...

#!/bin/bash 
declare -a array=( )                      # we build a 1-D-array
declare -a ncols=( )                      # we build a 1-D-array containing number of elements of each row

SEPARATOR="\t";
PADDING="";
MAXROWS=0;
index=0
indexCol=0
while read -a line; do
    ncols[$indexCol]=${#line[@]};
((indexCol++))
if [ ${#line[@]} -gt ${MAXROWS} ]
    then
         MAXROWS=${#line[@]}
    fi    
    for (( COUNTER=0; COUNTER<${#line[@]}; COUNTER++ )); do
        array[$index]=${line[$COUNTER]}
        ((index++))

    done
done < "$1"

for (( ROW = 0; ROW < MAXROWS; ROW++ )); do
  COUNTER=$ROW;
  for (( indexCol=0; indexCol < ${#ncols[@]}; indexCol++ )); do
if [ $ROW -ge ${ncols[indexCol]} ]
    then
      printf $PADDING
    else
  printf "%s" ${array[$COUNTER]}
fi
if [ $((indexCol+1)) -lt ${#ncols[@]} ]
then
  printf $SEPARATOR
    fi
    COUNTER=$(( COUNTER + ncols[indexCol] ))
  done
  printf "\n" 
done

2

আমি কোনও ধরণের ডেটা (সংখ্যা বা ডেটা) সহ কোনও ধরণের ম্যাট্রিক্স (এনএক্সএন বা এমএক্সএন) স্থানান্তর করার জন্য একটি সমাধান খুঁজছিলাম এবং নিম্নলিখিত সমাধান পেয়েছি:

Row2Trans=number1
Col2Trans=number2

for ((i=1; $i <= Line2Trans; i++));do
    for ((j=1; $j <=Col2Trans ; j++));do
        awk -v var1="$i" -v var2="$j" 'BEGIN { FS = "," }  ; NR==var1 {print $((var2)) }' $ARCHIVO >> Column_$i
    done
done

paste -d',' `ls -mv Column_* | sed 's/,//g'` >> $ARCHIVO

2

যদি আপনি কেবল একটি ফাইলের বাইরে একটি একক (কমা বিস্মৃত) লাইন grab N কে ধরতে চান এবং এটি একটি কলামে রূপান্তর করতে চান:

head -$N file | tail -1 | tr ',' '\n'

2

খুব মার্জিত নয়, তবে এই "একক-লাইন" কমান্ডটি সমস্যাটি দ্রুত সমাধান করে:

cols=4; for((i=1;i<=$cols;i++)); do \
            awk '{print $'$i'}' input | tr '\n' ' '; echo; \
        done

এখানে কলস হল কলামগুলির সংখ্যা, যেখানে আপনি 4 দ্বারা প্রতিস্থাপন করতে পারেন head -n 1 input | wc -w


2

awkআপনার কাছে থাকা মেমরির আকার সহ আরও একটি সমাধান এবং সীমিত ইনপুট।

awk '{ for (i=1; i<=NF; i++) RtoC[i]= (RtoC[i]? RtoC[i] FS $i: $i) }
    END{ for (i in RtoC) print RtoC[i] }' infile

এটি প্রতিটি একই ফাইল করা নম্বর পজিটোনকে একসাথে যুক্ত করে এবং ENDফলাফলটি প্রথম কলামের প্রথম সারি, দ্বিতীয় কলামে দ্বিতীয় সারিতে ইত্যাদি প্রিন্ট করে: আউটপুট:

X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11

2

কিছু * নিক্স মানক ওয়ান-লাইনার ব্যবহার করে, কোনও টেম্প ফাইলের প্রয়োজন হয় না। এনবি: ওপি একটি দক্ষ ফিক্স চেয়েছিল (অর্থাত্ দ্রুত), এবং শীর্ষের উত্তরগুলি সাধারণত এই উত্তরের চেয়ে দ্রুত হয়। এই ওয়ান-লাইনারগুলি তাদের জন্য যাঁরা * নিক্স সফ্টওয়্যার সরঞ্জামগুলি যে কোনও কারণেই চান। বিরল ক্ষেত্রে, ( যেমন বিরল আইও এবং মেমরি), এই স্নিপেটগুলি শীর্ষের উত্তরগুলির চেয়ে কিছুটা দ্রুত হতে পারে।

ইনপুট ফাইল foo কল করুন ।

  1. যদি আমরা জানি foo এর চারটি কলাম রয়েছে:

    for f in 1 2 3 4 ; do cut -d ' ' -f $f foo | xargs echo ; done
  2. Foo এর কতটি কলাম রয়েছে তা আমরা যদি না জানি :

    n=$(head -n 1 foo | wc -w)
    for f in $(seq 1 $n) ; do cut -d ' ' -f $f foo | xargs echo ; done

    xargsএকটি আকার সীমা আছে এবং তাই একটি দীর্ঘ ফাইল দিয়ে অসম্পূর্ণ কাজ করতে হবে। সিস্টেম নির্ভর কি আকারের সীমা, যেমন:

    { timeout '.01' xargs --show-limits ; } 2>&1 | grep Max

    কমান্ডের সর্বোচ্চ দৈর্ঘ্য আমরা আসলে ব্যবহার করতে পারি: 2088944

  3. trএবং echo:

    for f in 1 2 3 4; do cut -d ' ' -f $f foo | tr '\n\ ' ' ; echo; done

    ... বা যদি কলামগুলির # টি অজানা:

    n=$(head -n 1 foo | wc -w)
    for f in $(seq 1 $n); do 
        cut -d ' ' -f $f foo | tr '\n' ' ' ; echo
    done
  4. ব্যবহার করে set, যা পছন্দ xargs, অনুরূপ কমান্ড লাইন আকার ভিত্তিক সীমাবদ্ধতা আছে:

    for f in 1 2 3 4 ; do set - $(cut -d ' ' -f $f foo) ; echo $@ ; done

2
এগুলি হ'ল একটি উত্তেজক বা পার্ল সমাধান এবং ভঙ্গুর চেয়ে ধীর গতির আকার হবে। Unix.stackexchange.com / জিজ্ঞাসা / 169716/ … পড়ুন ।
এড মর্টন

@ এডমার্টন, ধন্যবাদ, আপনার গতির উদ্বেগের সমাধান করার জন্য আমার উত্তরটির যোগ্যতা অর্জন করেছে। পুনরায় "ভঙ্গুর": 3 নয় ) এবং যখন প্রোগ্রামার জানে না তখন কোনও প্রদত্ত কৌশলটির জন্য ডেটা নিরাপদ থাকে; এবং পসিক্স সামঞ্জস্যপূর্ণ শেল কোড পার্লের চেয়ে বেশি স্থিতিশীল মান নয় ?
এজিসি

দুঃখিত, পার্ল সম্পর্কে idk। এক্ষেত্রে ব্যবহারের সরঞ্জামটি হবে awkcut, head, echo, ইত্যাদি কোন POSIX সামঞ্জস্যপূর্ণ শেল কোড একটি তুলনায় awkস্ক্রিপ্ট হয় - তারা সব যে ইউনিক্স ইনস্টলেশনের উপর মান। এমন সরঞ্জামগুলির সেট ব্যবহার করার কোনও কারণ নেই যা সংমিশ্রণে আপনাকে আপনার ইনপুট ফাইল এবং যে স্ক্রিপ্টটি আপনি স্ক্রিপ্টটি সম্পাদন করেন সেই সময় থেকে যখন আপনি কেবল খালি ব্যবহার করতে পারেন এবং শেষ ফলাফলটি তত দ্রুত এবং আরও শক্তিশালী হওয়া সম্পর্কে সতর্ক থাকতে হবে ।
এড মর্টন

প্লিজ, আমি বিরোধী নই awk কিন্তু অবস্থার পরিবর্তিত হয়। কারণ # 1: for f in cut head xargs seq awk ; do wc -c $(which $f) ; done যখন সঞ্চয়স্থান খুব ধীর হয় বা IO খুব কম হয়, বড় দোভাষীরা আরও আদর্শ পরিস্থিতিতে তারা যতই ভাল থাকুক না কেন বিষয়গুলিকে আরও খারাপ করে তোলে। কারণ # 2: অজাদ , (বা বেশিরভাগ ভাষা), কোনও কাজ ভাল করার জন্য ডিজাইন করা ছোট ব্যবহারের চেয়ে স্টিপার লার্নিং বক্ররেখায় ভুগছে। রান-টাইম যখন কোডার ম্যান আওয়ারের চেয়ে সস্তা হয়, "সফ্টওয়্যার সরঞ্জামগুলি" দিয়ে সহজে কোডিং অর্থ সাশ্রয় করে।
এগ্রি

1
#!/bin/bash

aline="$(head -n 1 file.txt)"
set -- $aline
colNum=$#

#set -x
while read line; do
  set -- $line
  for i in $(seq $colNum); do
    eval col$i="\"\$col$i \$$i\""
  done
done < file.txt

for i in $(seq $colNum); do
  eval echo \${col$i}
done

সঙ্গে অন্য সংস্করণ set eval


সেই সমাধানের সমস্যার কিছু, তবে সবকটিই বোঝার জন্য unix.stackexchange.com/questions/169716/… পড়ুন ।
এড মর্টন

1

আর একটি বাশ বৈকল্পিক

$ cat file 
XXXX    col1    col2    col3
row1    0       1       2
row2    3       4       5
row3    6       7       8
row4    9       10      11

লিপি

#!/bin/bash

I=0
while read line; do
    i=0
    for item in $line; { printf -v A$I[$i] $item; ((i++)); }
    ((I++))
done < file
indexes=$(seq 0 $i)

for i in $indexes; {
    J=0
    while ((J<I)); do
        arr="A$J[$i]"
        printf "${!arr}\t"
        ((J++))
    done
    echo
}

আউটপুট

$ ./test 
XXXX    row1    row2    row3    row4    
col1    0       3       6       9   
col2    1       4       7       10  
col3    2       5       8       11

0

এখানে একটি হাস্কেল সমাধান রয়েছে। -O2 দিয়ে সংকলিত হয়ে গেলে, এটি বারবার "হ্যালো ওয়ার্ল্ড" ইনপুট লাইনগুলির জন্য স্টিফেনের পাতলা মোড়ক সি পাইথনটির চেয়ে আমার মেশিনে ঘোস্টডগের বিশ্রী তুলনায় কিছুটা দ্রুত এবং ধীরে ধীরে চলে। দুর্ভাগ্যক্রমে কমান্ড লাইন কোডটি পাস করার জন্য জিএইচসির সমর্থন যতদূর আমি বলতে পারি তা অস্তিত্বহীন, সুতরাং আপনাকে এটি একটি ফাইলে লিখতে হবে। এটি সংক্ষিপ্ততম সারির দৈর্ঘ্যে সারিগুলি কেটে যাবে।

transpose :: [[a]] -> [[a]]
transpose = foldr (zipWith (:)) (repeat [])

main :: IO ()
main = interact $ unlines . map unwords . transpose . map words . lines

0

একটি অজানা সমাধান যা মেমরিতে পুরো অ্যারে সঞ্চয় করে

    awk '$0!~/^$/{    i++;
                  split($0,arr,FS);
                  for (j in arr) {
                      out[i,j]=arr[j];
                      if (maxr<j){ maxr=j}     # max number of output rows.
                  }
            }
    END {
        maxc=i                 # max number of output columns.
        for     (j=1; j<=maxr; j++) {
            for (i=1; i<=maxc; i++) {
                printf( "%s:", out[i,j])
            }
            printf( "%s\n","" )
        }
    }' infile

তবে আমরা আউটপুট সারিগুলির যতবার প্রয়োজন ফাইলটিকে "হাঁটা" করতে পারি:

#!/bin/bash
maxf="$(awk '{if (mf<NF); mf=NF}; END{print mf}' infile)"
rowcount=maxf
for (( i=1; i<=rowcount; i++ )); do
    awk -v i="$i" -F " " '{printf("%s\t ", $i)}' infile
    echo
done

যা (আউটপুট সারিগুলির একটি স্বল্প গণনার জন্য পূর্ববর্তী কোডের চেয়ে দ্রুত)।


0

এখানে বাশ ওয়ান-লাইনার রয়েছে যা প্রতিটি লাইনকে কেবল একটি কলামে রূপান্তর করতে এবং pasteসেগুলি একসাথে তৈরি করার উপর ভিত্তি করে তৈরি হয় :

echo '' > tmp1;  \
cat m.txt | while read l ; \
            do    paste tmp1 <(echo $l | tr -s ' ' \\n) > tmp2; \
                  cp tmp2 tmp1; \
            done; \
cat tmp1

m.txt:

0 1 2
4 5 6
7 8 9
10 11 12
  1. tmp1ফাইল তৈরি করে তাই এটি খালি নয়।

  2. প্রতিটি লাইন পড়ে এবং ব্যবহার করে এটি একটি কলামে রূপান্তর করে tr

  3. tmp1ফাইলটিতে নতুন কলামটি আটকায়

  4. অনুলিপিগুলি এর মধ্যে ফিরে আসে tmp1

পিএস: আমি সত্যই আইও-বর্ণনাকারী ব্যবহার করতে চেয়েছিলাম কিন্তু সেগুলিতে কাজ করতে পারি নি।


আপনি যদি একটি বড় ফাইলে এটি চালিয়ে যাচ্ছেন তবে একটি অ্যালার্ম ঘড়ি সেট করা নিশ্চিত করুন। সেই পদ্ধতির সমস্যাগুলির কিছু বোঝার জন্য unix.stackexchange.com/questions/169716/… পড়ুন ।
এড মর্টন

0

একটি অনেলাইনার আর ব্যবহার করে ...

  cat file | Rscript -e "d <- read.table(file('stdin'), sep=' ', row.names=1, header=T); write.table(t(d), file=stdout(), quote=F, col.names=NA) "

0

আমি আগে দুটি অনুরূপ ক্রিয়াকলাপ করতে নীচে দুটি স্ক্রিপ্ট ব্যবহার করেছি। প্রথমটি বিশ্রীতে রয়েছে যা দ্বিতীয়টির চেয়ে অনেক দ্রুত যা "খাঁটি" বাশে আছে। আপনি এটি আপনার নিজের প্রয়োগের সাথে খাপ খাইয়ে নিতে সক্ষম হতে পারেন।

awk '
{
    for (i = 1; i <= NF; i++) {
        s[i] = s[i]?s[i] FS $i:$i
    }
}
END {
    for (i in s) {
        print s[i]
    }
}' file.txt
declare -a arr

while IFS= read -r line
do
    i=0
    for word in $line
    do
        [[ ${arr[$i]} ]] && arr[$i]="${arr[$i]} $word" || arr[$i]=$word
        ((i++))
    done
done < file.txt

for ((i=0; i < ${#arr[@]}; i++))
do
    echo ${arr[i]}
done
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.