123

我有一个巨大的制表符分隔文件,格式如下

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

我想只使用 bash 命令以一种有效的方式转置它(我可以编写一个十左右行的 Perl 脚本来做到这一点,但它的执行速度应该比本机 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 的解决方案,但它仍然太慢了。有什么想法/建议/绝妙的想法吗?:-)

4

31 回答 31

125
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

Jonathan 在 10000 行文件上针对 Perl 解决方案的性能

$ 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

由 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(当然,旧的、损坏的 awk 除外——还有 YMMV)。

上述解决方案确实将整个文件读入内存 - 如果输入文件太大,那么您可以这样做:

$ 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 awkENDFILE和 ,ARGIND但任何 awk 都可以对FNR==1和进行相同的测试END

于 2009-11-13T15:34:46.363 回答
63

rs

rs是一个 BSD 实用程序,它也随 macOS 一起提供,但它可以从其他平台上的包管理器中获得。它以 APL 中的 reshape 函数命名。

使用空格和制表符序列作为列分隔符:

rs -T

使用制表符作为列分隔符:

rs -c -C -T

使用逗号作为列分隔符:

rs -c, -C, -T

-c更改输入列分隔符并-C更改输出列分隔符。一个单独的-c-C将分隔符设置为制表符。-T转置行和列。

不要使用-t代替-T,因为它会自动选择输出列数,以便输出行填充显示的宽度(默认为 80 个字符,但可以使用 更改-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 -c, -C, -T<<<$'1,\n3,4'
1,3,4,

呆呆

$ seq 4|paste -d, - -|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?"\n":FS),a[i][j]}' FS=,
1,3
2,4

这使用数组的数组,这是一个gawk扩展。macOSnawk从 2007 年开始提供不支持数组数组的版本。

要将空格用作分隔符而不折叠空格和制表符序列,请使用FS='[ ]'.

红宝石

$ seq 4|paste -d, - -|ruby -e'STDIN.map{|x|x.chomp.split(",",-1)}.transpose.each{|x|puts x*","}'
1,3
2,4

禁用最后丢弃空字段的-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", "", "\tb", ""]
$ ruby -e'p" a  \tb ".split(" ",-1)'
["a", "b", ""]

jq

tp(){ jq -R .|jq --arg x "${1-$'\t'}" -sr 'map(./$x)|transpose|map(join($x))[]';}

jq -R .将每个输入行打印为 JSON 字符串文字,-s( --slurp) 在将每行解析为 JSON 后为输入行创建一个数组,并且-r( --raw-output) 输出字符串的内容而不是 JSON 字符串文字。运算符重载以/拆分字符串。

R

$ printf %s\\n 1,2 3,4|Rscript -e 'write.table(t(read.table("stdin",sep=",")),"",sep=",",quote=F,col.names=F,row.names=F)'
1,3
2,4

如果您替换RscriptR,它会将正在运行的代码回显到 STDOUT。如果在读取整个 STDIN 之前出现ignoring SIGPIPE signal类似退出的命令,也会导致错误。head -n1

write.table当输出文件的参数为空字符串时,打印到 STDOUT。

于 2015-05-11T17:28:41.497 回答
32

一个 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))

此代码确实假定每一行具有相同数量的列(不执行填充)。

于 2009-11-13T17:21:00.923 回答
22

sourceforge 上的transpose项目正是一个类似 coreutil 的 C 程序。

gcc transpose.c -o transpose
./transpose -t input > output #works with stdin, too.
于 2013-02-08T17:36:25.637 回答
21

看看可以datamash transpose. 未来版本还将支持交叉表(数据透视表)

以下是使用空格分隔的列的方法:

datamash transpose -t ' ' < file > transposed_file
于 2016-01-07T09:08:01.537 回答
17

纯 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
于 2009-11-19T15:11:58.387 回答
11

GNU datamash非常适合这个问题,只有一行代码和可能任意大的文件大小!

datamash -W transpose infile > outfile
于 2017-09-07T15:00:34.403 回答
9

这是一个中等强度的 Perl 脚本来完成这项工作。@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 的性能略优于 awk - 0.026 秒对 0.042 秒。两者都不太可能成为问题。


MacOS X 10.5.8 上的 Perl 5.10.1(32 位)与 awk(版本 20040207,给出“-V”时)与 gawk 3.1.7(32 位)的代表性时序,文件包含 10,000 行,每行 5 列线:

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 慢。显然,您的里程会有所不同。

于 2009-11-14T19:54:04.930 回答
9

有一个专门为此构建的实用程序,

GNU datamash 实用程序

apt install datamash  

datamash transpose < yourfile

取自该站点,https://www.gnu.org/software/datamash/http://www.thelinuxrain.com/articles/transposing-rows-and-columns-3-methods

于 2017-04-07T09:00:40.443 回答
7

假设你所有的行都有相同数量的字段,这个 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
于 2015-06-10T17:57:51.537 回答
6

如果你已经sc安装了,你可以这样做:

psc -r < inputfile | sc -W% - > outputfile
于 2009-11-13T16:54:28.947 回答
5

我通常使用这个小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初始文件具有的最大列数,以便将其用作要打印的行数。

于 2015-05-12T07:48:30.650 回答
3

一个骇人听闻的 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;
于 2009-11-13T15:49:11.607 回答
3

我可以看到您自己的示例的唯一改进是使用 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
于 2009-11-13T16:08:51.030 回答
3

一些*nix标准实用程序单行,不需要临时文件。注意:OP 想要一个有效的修复(即更快),而最佳答案通常比这个答案更快。 无论出于何种原因,这些单线都是为喜欢*nix 软件工具的人准备的。在极少数情况下,(例如稀缺的 IO 和内存),这些片段实际上可能比一些最佳答案更快。

调用输入文件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. Using set, which likexargs具有类似的基于命令行大小的限制:

    for f in 1 2 3 4 ; do set - $(cut -d ' ' -f $f foo) ; echo $@ ; done
    
于 2016-04-10T10:52:41.310 回答
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
于 2010-03-21T22:39:57.687 回答
2

我只是在寻找类似的 bash 转置,但支持填充。这是我根据 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
于 2014-01-30T05:27:17.500 回答
2

不是很优雅,但是这个“单行”命令可以快速解决问题:

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

这里 cols 是列数,您可以将 4 替换为head -n 1 input | wc -w.

于 2014-05-06T21:41:21.810 回答
2

我正在寻找一种解决方案,用任何类型的数据(数字或数据)转置任何类型的矩阵(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
于 2014-08-06T01:10:29.683 回答
2

如果您只想从文件中获取单个(逗号分隔)行 $N 并将其转换为列:

head -$N file | tail -1 | tr ',' '\n'
于 2014-11-06T12:06:48.387 回答
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
于 2018-09-19T16:51:14.803 回答
1

这是一个 Bash one-liner,它基于简单地将每一行转换为一列并将paste它们 -ing 在一起:

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.

PS:我真的很想使用 io-descriptors 但无法让它们工作。

于 2014-12-07T03:08:45.357 回答
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

于 2015-08-19T07:43:32.797 回答
1

另一个 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
于 2020-02-28T06:00:52.473 回答
0

这是一个 Haskell 解决方案。当使用 -O2 编译时,它的运行速度比 ghostdog 的 awk 稍快,而在我的机器上重复“Hello world”输入行时,它的运行速度比 Stephan 的薄包装 c python 稍慢。不幸的是,据我所知,GHC 对传递命令行代码的支持并不存在,因此您必须自己将其写入文件。它会将行截断为最短行的长度。

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

main :: IO ()
main = interact $ unlines . map unwords . transpose . map words . lines
于 2014-08-26T03:03:40.417 回答
0

将整个数组存储在内存中的 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

哪个(对于低数量的输出行比前面的代码更快)。

于 2016-01-28T22:46:04.777 回答
0

使用 R 的 oneliner...

  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) "
于 2020-02-27T12:53:15.360 回答
0

我之前使用过以下两个脚本来执行类似的操作。第一个是在 awk 中,它比在“纯”bash 中的第二个要快得多。您也许可以将其调整到您自己的应用程序中。

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
于 2020-04-02T02:10:55.160 回答
0

简单的 4 行答案,保持可读性。

col="$(head -1 file.txt | wc -w)"
for i in $(seq 1 $col); do
    awk '{ print $'$i' }' file.txt | paste -s -d "\t"
done
于 2020-09-17T07:32:04.743 回答
0

我玩游戏有点晚了,但是这个怎么样:

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

于 2021-10-12T17:40:18.123 回答
0
for i in $(seq $(head -n1 file.txt | tr ' ' '\n' | wc -l))
do
  cut -d' ' -f"$i" file.txt | paste -s -d' ' -
done

或者

seq $(head -n1 file.txt | tr " " "\n" | wc -l) | xargs -I{} sh -c 'cut -d" " -f"{}" file.txt | paste -s -d" " -'
于 2021-12-08T16:14:09.377 回答