An efficient way to transpose a file in Bash

前端 未结 29 2721
时光说笑
时光说笑 2020-11-22 03:30

I have a huge tab-separated file formatted like this

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

I would like t

29条回答
  •  半阙折子戏
    2020-11-22 03:40

    Some *nix standard util one-liners, no temp files needed. NB: the OP wanted an efficient fix, (i.e. faster), and the top answers are usually faster than this answer. These one-liners are for those who like *nix software tools, for whatever reasons. In rare cases, (e.g. scarce IO & memory), these snippets can actually be faster than some of the top answers.

    Call the input file foo.

    1. If we know foo has four columns:

      for f in 1 2 3 4 ; do cut -d ' ' -f $f foo | xargs echo ; done
      
    2. If we don't know how many columns foo has:

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

      xargs has a size limit and therefore would make incomplete work with a long file. What size limit is system dependent, e.g.:

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

      Maximum length of command we could actually use: 2088944

    3. tr & echo:

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

      ...or if the # of columns are unknown:

      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 like xargs, has similar command line size based limitations:

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

提交回复
热议问题