Bash에서 파일을 효율적으로 변환하는 방법
이렇게 포맷된 큰 탭 구분 파일이 있습니다.
X column1 column2 column3
row1 0 1 2
row2 3 4 5
row3 6 7 8
row4 9 10 11
bash 명령어만을 사용하여 효율적으로 변환하고 싶다(Perl 스크립트를 10줄 정도 쓸 수 있지만 네이티브 bash 함수보다 실행 속도가 느릴 수 있다).따라서 출력은 다음과 같아야 합니다.
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의 솔루션을 확인했지만, 아직 너무 느립니다.아이디어/제안/명석한 아이디어가 있습니까? :-)
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
Perl 솔루션에 대한 Jonathan의 퍼포먼스 (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
Edit by Ed Morton (@ghostdog74가 동의하지 않으면 자유롭게 삭제 가능)
보다 명확한 변수 이름을 가진 이 버전은 아래 질문에 대한 답변과 스크립트의 동작을 명확하게 하는 데 도움이 될 수 있습니다.또한 OP가 원래 요청한 구분 기호로 탭을 사용하여 빈 필드를 처리하며, 공교롭게도 이 경우 출력이 약간 프리페이트업합니다.
$ 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
위의 솔루션은 모든 awk에서 작동합니다(물론 YMMV는 오래된 Awk가 파손된 것은 제외).
위의 솔루션에서는 파일 전체를 메모리에 읽어 들일 수 있습니다.입력 파일이 너무 크면 다음과 같이 할 수 있습니다.
$ 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
메모리는 거의 사용하지 않지만 입력 파일을 한 줄의 필드 수당 한 번 읽기 때문에 파일 전체를 메모리로 읽는 버전보다 속도가 훨씬 느려집니다., 각 을 전제로 , 「」에 GNU 를 합니다.ENDFILE
★★★★★★★★★★★★★★★★★」ARGIND
어떤 도 같은 할 수 .FNR==1
★★★★★★★★★★★★★★★★★」END
.
아악
어레이 어레이를 사용하는 Gawk 버전:
tp(){ awk '{for(i=1;i<=NF;i++)a[i][NR]=$i}END{for(i in a)for(j in a[i])printf"%s"(j==NR?RS:FS),a[i][j]}' "${1+FS=$1}";}
다차원 어레이를 사용하는 일반 awk 버전(벤치마크에서는 약 2배 느림):
tp(){ awk '{for(i=1;i<=NF;i++)a[i,NR]=$i}END{for(i=1;i<=NF;i++)for(j=1;j<=NR;j++)printf"%s"(j==NR?RS:FS),a[i,j]}' "${1+FS=$1}";}
에는 Brian 버전(Brian Kingham)이 .nawk
어레이 어레이를 지원하지 않습니다.
않고 하려면 을 합니다.FS='[ ]'
.
rs
rs
는 MacOS와 함께 제공되는 BSD 유틸리티이지만 다른 플랫폼의 패키지 매니저에서 사용할 수 있습니다.APL을 사용하다
공백 및 탭 시퀀스를 열 구분 기호로 사용합니다.
rs -T
탭을 열 구분 기호로 사용:
rs -c -C -T
열 구분 기호로 쉼표 사용:
rs -c, -C, -T
-c
열 기호와 입력 열 구분 기호를 합니다.-C
을 사용하다 홀 a.-c
★★★★★★★★★★★★★★★★★」-C
구분 기호를 탭으로 설정합니다. -T
행과 열을 바꿉니다.
「 」를하지 주세요.-t
-T
이지만 "로할 수 ")가 -w
를 참조해 주세요.
가 " " " 를 사용하여 -C
되지만, 는 " " "로 할 수 . "로 할 수 있습니다.sed
:
$ seq 4|paste -d, - -|rs -c, -C, -T
1,3,
2,4,
$ seq 4|paste -d, - -|rs -c, -C, -T|sed s/.\$//
1,3
2,4
rs -T
는 첫 열첫의 빈열로 잘못된 를 생성합니다. 즉, " " " " " " " " " " " " " 입니다.
$ rs -c, -C, -T<<<$'1,\n3,4'
1,3,4,
R
t
함수는 행렬 또는 데이터 프레임을 바꿉니다.
Rscript -e 'write.table(t(read.table("stdin",sep=",",quote="",comment.char="")),sep=",",quote=F,col.names=F,row.names=F)'
「」를 .Rscript -e
R -e
으로 STDOUT로되고 있는 「Da」 「STDOUT」도 ignoring SIGPIPE signal
에 R 명령어가 head -n1
STDN을 읽기 전에 출발합니다.STDIN 전체를 읽기 전에 종료됩니다.
quote=""
입력이 두 번 인용하거나 단일 인용되지 않은 경우, doesn 는 은 함 다 할 제 은 경 can 습우삭 니 수 않 quotes input있 the quotes orcomment.char=""
입력이 해시 문자를 포함하지 않으면 제거할 수 있습니다.해시 문자로 시작하는 행이 입력에 포함되지 않은 경우 를 삭제할 수 있습니다.
For a big input file, 대용량 입력 파일의 경우,fread
★★★★★★★★★★★★★★★★★」fwrite
부에서data.table
are faster than 보다 빠르다read.table
★★★★★★★★★★★★★★★★★」write.table
:
$ seq 1e6|awk 'ORS=NR%1e3?FS:RS'>a
$ time Rscript --no-init-file -e 'write.table(t(read.table("a")),quote=F,col.names=F,row.names=F)'>/dev/null
real 0m1.061s
user 0m0.983s
sys 0m0.074s
$ time Rscript --no-init-file -e 'write.table(t(data.table::fread("a")),quote=F,col.names=F,row.names=F)'>/dev/null
real 0m0.599s
user 0m0.535s
sys 0m0.048s
$ time Rscript --no-init-file -e 'data.table::fwrite(t(data.table::fread("a")),sep=" ",col.names=F)'>t/b
x being coerced from class: matrix to data.table
real 0m0.375s
user 0m0.296s
sys 0m0.073s
jq
tp(){ jq -R .|jq --arg x "${1-$'\t'}" -sr 'map(./$x)|transpose|map(join($x))[]';}
jq -R .
는, 각 리터럴로서 합니다.-s
)--slurp
는 각 후또, 「 JSON」은 「JSON」으로 해석합니다.-r
)--raw-output
리터럴이 는 JSON 문자열 리터럴이 아닌 문자열의 내용을 출력합니다./
연산자가 문자열을 분할하기 위해 오버로드되었습니다.
루비
ruby -e'STDIN.map{|x|x.chomp.split(",",-1)}.transpose.each{|x|puts x*","}'
-1
합니다.split
에 빈 합니다.
$ ruby -e'p"a,,".split(",")'
["a"]
$ ruby -e'p"a,,".split(",",-1)'
["a", "", ""]
기능 양식:
$ tp(){ ruby -e's=ARGV[0];STDIN.map{|x|x.chomp.split(s==" "?/ /:s,-1)}.transpose.each{|x|puts x*s}' -- "${1-$'\t'}";}
$ seq 4|paste -d, - -|tp ,
1,3
2,4
는 " " " 를 사용합니다.s==" "?/ /:s
'인수'에 split
함수는 단일 공간이며 연속된 공간 및 탭에 따라 문자열이 분할되는 awk와 같은 특별한 동작을 가능하게 합니다.
$ ruby -e'p" a \tb ".split(" ",-1)'
["a", "b", ""]
$ ruby -e'p" a \tb ".split(/ /,-1)'
["", "a", "", "\tb", ""]
Python 솔루션:
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))
이 코드는 모든 행에 동일한 수의 열이 있다고 가정합니다(패딩은 수행되지 않음).
다음과 같이 사용할 수 있는 GNU datamash를 확인하십시오.datamash transpose
테이블 table도할 예정입니다. 표
공백으로 구분된 열을 사용하는 방법은 다음과 같습니다.
datamash transpose -t ' ' < file > transposed_file
소스 포지에 대한 전치 프로젝트는 정확히 그것을 위한 코어유틸과 같은 C 프로그램입니다.
gcc transpose.c -o transpose
./transpose -t input > output #works with stdin, too.
순수 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\t" ${array[$COUNTER]}
done
printf "\n"
done
GNU datamash는 한 줄의 코드와 잠재적으로 큰 파일 크기를 가진 이 문제에 완벽하게 적합합니다.
datamash -W transpose infile > outfile
이를 위해 특별히 제작된 유틸리티가 있습니다.
apt install datamash
datamash transpose < yourfile
이 사이트, http://www.thelinuxrain.com/articles/transposing-rows-and-columns-3-methods 및 http://www.thelinuxrain.com/articles/transposing-rows-and-columns-3-methods에서 가져온 정보입니다.
이 작업을 수행하기 위한 중간 정도의 견고한 Perl 스크립트를 다음에 나타냅니다.@@ghostdog74의 @ghostdog74의 @ghostdog74의 @ghostdog74의 @ghostdog74와 구조적 유사점이 있다.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";
}
샘플 데이터 크기에서는 perl과 awk의 성능 차이는 무시할 수 있습니다(총 7개 중 1밀리초).더 큰 데이터 세트(100x100 매트릭스, 엔트리 각각6~8 문자)에서는 perl은 0.026s 대 0.042s의 awk를 약간 웃돌았습니다.어느 쪽도 문제가 되지 않을 것 같다.
MacOS X 10.5.8의 Perl 5.10.1(32비트) vs awk('-V'가 지정된 경우 버전 20040207) vs gawk 3.1.7(32비트)에 대한 대표적인 타이밍은 다음과 같습니다.
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:
gawk는 이 머신의 awk보다 훨씬 빠르지만 perl보다는 여전히 느립니다.물론 주행거리는 다양합니다.
모든 행의 필드 수가 같다고 가정하면 이 awk 프로그램은 문제를 해결합니다.
{for (f=1;f<=NF;f++) col[f] = col[f]":"$f} END {for (f=1;f<=NF;f++) print col[f]}
각 각 루프를 합니다.f
를 col[f]
해당 필드의 요소를 포함합니다.모든 행을 완료한 후 각 문자열을 별도의 행으로 인쇄합니다.':'로 바꾸면 . 로 할 때 ':'로합니다.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
인스톨 되어 있는 경우는, 다음의 조작을 실행할 수 있습니다.
psc -r < inputfile | sc -W% - > outputfile
는 보통 이 i i i i i i i i i i 。awk
: "snippet" :
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
첫 번째 파일에 있는 열의 imum 양으로, 인쇄하는 행의 수로 사용됩니다.
해키쉬한 perl 솔루션은 다음과 같습니다.모든 파일을 메모리에 로드하지 않고 중간 임시 파일을 인쇄한 다음 모든 놀라운 붙여넣기를 사용할 수 있기 때문에 좋습니다.
#!/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;
고객님의 예에서 유일하게 개선되는 점은 awk를 사용하는 것입니다.이것에 의해, 실행되는 프로세스의 수와 그 사이에 파이핑 되는 데이터의 양이 삭감됩니다.
/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
일부 *nix 표준 util 1라인. 임시 파일은 필요하지 않습니다.NB: OP는 효율적인 수정(즉, 빠른 수정)을 원했습니다.상위 답변은 보통 이 답변보다 빠릅니다.이 원라인은 *nix 소프트웨어 툴을 좋아하는 분들을 위한 것입니다.드문 경우(예: 입출력 및 메모리 부족) 이러한 스니펫은 실제로 상위 답변보다 빠를 수 있습니다.
입력 파일 foo를 호출합니다.
foo에 4개의 열이 있는 경우:
for f in 1 2 3 4 ; do cut -d ' ' -f $f foo | xargs echo ; done
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
실제로 사용할 수 있는 최대 명령어 길이: 208894
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
「」를 사용합니다.
set
를 들면, 「」와 같이 됩니다.xargs
에는 다음과 같은 명령줄 크기 기반 제한이 있습니다.for f in 1 2 3 4 ; do set - $(cut -d ' ' -f $f foo) ; echo $@ ; done
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
나는 단지 비슷한 bash tranpose를 찾고 있었지만 패딩에 대한 지원이 있었다.여기 fgm의 솔루션을 바탕으로 작성한 스크립트가 효과가 있을 것 같습니다.도움이 된다면...
#!/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
모든 종류의 매트릭스(nxn 또는 mxn)를 모든 종류의 데이터(숫자 또는 데이터)와 치환할 수 있는 솔루션을 찾고 있었는데 다음과 같은 솔루션을 얻었습니다.
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
파일에서 $N 행만 가져와 열로 변환하는 경우:
head -$N file | tail -1 | tr ',' '\n'
그다지 우아하지는 않지만, 이 "단일 행" 명령어는 문제를 빠르게 해결합니다.
cols=4; for((i=1;i<=$cols;i++)); do \
awk '{print $'$i'}' input | tr '\n' ' '; echo; \
done
, 를 4로 대체할 수 .head -n 1 input | wc -w
.
하나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
#!/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
에서는 각 하고 "Bash"를 "Bash"로 한 Bash 줍니다.각 행을 컬럼으로 변환하고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
작성하다
tmp1
파일이 비어있지 않습니다.행을 합니다.
tr
을 붙입니다.
tmp1
tmp1
.
PS: io-descriptor를 꼭 사용하고 싶었지만 작동하지 않았습니다.
다른 bash 배리언트
$ 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
게임에 조금 늦었지만 이건 어때?
cat table.tsv | python -c "import pandas as pd, sys; pd.read_csv(sys.stdin, sep='\t').T.to_csv(sys.stdout, sep='\t')"
★★★★★★★★★★★★★★★★★」zcat
퍼퍼면면면면면면면
있다고 하는 것입니다.pandas
의 「」에 되어 있습니다.python
여기 아주 간단한 루비가 있습니다.
ruby -lane 'BEGIN{lines=[]}
lines<<$F
END{lines.transpose.each{|row| puts row.join("\t")}}' file
, 「 」, 「 」, 「 」, 「 」의 커맨드 라인 하지 않고, 분할을 할 수 .-lan
:
ruby -e '$<.read.
split(/\R+/).
map(&:split).
transpose.each{|row| puts row.join("\t")}' file
또는 Ruby의 CSV 모듈을 사용할 수 있습니다.
ruby -r csv -e '
tbl=CSV.parse($<.read, **{:headers=>false, :col_sep=>" "}) # or use :col_sep=>"\t" for tab columns
tbl.transpose.each{|row| puts row.join("\t")}
' file
인쇄물:
X row1 row2 row3 row4
column1 0 3 6 9
column2 1 4 7 10
column3 2 5 8 11
여기 Haskell 솔루션이 있습니다.-O2로 컴파일하면 ghostdog's awk보다 약간 빠르고 Stephan의 얇은 c python보다 약간 느립니다.유감스럽게도 GHC의 명령줄 코드 전달 지원은 제가 알기로는 존재하지 않기 때문에 직접 파일에 작성해야 합니다.그러면 행이 가장 짧은 행의 길이로 잘립니다.
transpose :: [[a]] -> [[a]]
transpose = foldr (zipWith (:)) (repeat [])
main :: IO ()
main = interact $ unlines . map unwords . transpose . map words . lines
어레이 전체를 메모리에 저장하는 awk 솔루션
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
어느 쪽(출력 행의 카운트가 작을 경우 이전 코드보다 빠릅니다).
R을 사용하는 오네라이너...
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) "
이하의 2개의 스크립트를 사용해 같은 조작을 실시한 적이 있습니다.첫 번째는 awk로 "순수한" 배시의 두 번째보다 훨씬 더 빠릅니다.자신의 어플리케이션에 맞게 조정할 수 있을지도 모릅니다.
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
언급URL : https://stackoverflow.com/questions/1729824/an-efficient-way-to-transpose-a-file-in-bash
'programing' 카테고리의 다른 글
Swift: 빈 사전을 선언합니다. (0) | 2023.04.19 |
---|---|
.gitignore가 일부 파일을 제외한 모든 파일을 무시하도록 합니다. (0) | 2023.04.19 |
Tree View 전체를 강조 표시WPF의 항목 행 (0) | 2023.04.19 |
Bash 스크립트에서 프로그램이 존재하는지 확인하려면 어떻게 해야 합니까? (0) | 2023.04.19 |
MVVM을 통한 적절한 검증 (0) | 2023.04.19 |