Как переносить текстовый файл на основе символов

Есть некоторые инструменты, такие как datamesh для переноса матрицы в файл csv , но я хочу обмениваться строками и столбцами на основе символов. Итак, файл

 abcde fghij klmn opqrs 

должен стать

 afko bglq chmq dinr ej s 

Обратите внимание, что поскольку строка 3 короче, в последней строке должно быть вставлено пробельное пространство.

Из источника я мог написать некоторую программу на C, чтобы сделать это, но я думал, что однажды нашел инструмент для этого, но моя поисковая система не помогает мне найти его.

3 Solutions collect form web for “Как переносить текстовый файл на основе символов”

Вы можете сделать это с помощью утилиты rs в режиме чистого транспонирования ( -T ) – если вы правильно вставляете входные данные, т. Е.

 $ sed -e 's/./& /g' -e 's/ $//' file abcde fghij klmn opqrs 

(или, если у вас есть GNU sed, вы можете использовать sed 's/./ &/2g' ; другой вариант использует цикл sed -E ':a; s/([^ ])([^ ])/\1 \2/; ta' ); тогда

 $ sed -e 's/./& /g' -e 's/ $//' file | rs -Tng0 afko bglp chmq dinr ej s 

Важными параметрами являются:

  • -T чисто транспонировать
  • -n pad null entries
  • -g0 установить ширину выходного желоба (межколоночное расстояние) до нуля

В качестве альтернативы, выполните разделение ввода с помощью awk с пустым разделителем полей ввода и разделителем полей вывода по умолчанию:

 awk '{$1=$1} 1' FS= file | rs -Tng0 

Следующее общее решение для транспонирования с awk.

Для правильной работы нам нужно количество столбцов.
Это можно найти при чтении файла в массив значений:

 #!/bin/bash file=i4 delimiter="" sep="" transpose() { : # comment sed for newer awks. # Do this to separate characters in quite old awk # very old wak does not allow that the FS could be Null. #sed -e 's/./ &/g' "$file" | awk ' { for(i=1;i<=NF;i++){a[NR,i]=$i};{(NF>m)?m=NF:0} } END { for(j=1; j<=m; j++) { for(i=1; i<=NR; i++) { b=((a[i,j]=="")?" ":a[i,j]) printf("%s%s",(i==1)?"":sep,b) } printf("\n") } } ' FS="$delimiter" sep="$sep" cc="$countcols" <"$file" } transpose 

С этим файлом:

 abc fghij klmn opqrs 

Будет печать:

 afko bglp chmq inr js 

Awk позаботится о разделении символов, если «разделитель полей» равен нулю.
Символы печатаются в одной строке, если переменная sep также равна нулю.


Если awk является более старым, нулевой FS недействителен. Используйте следующие две команды.

Чтобы подсчитать количество символов, используйте это в старых awks:

 # Work with any POSIX awk to find the max character count in all rows. countcols=$(awk '{l=length($0);(l>max)?max=l:0}END{print max}' < "$file") 

Для выполнения транспозиции пространство может быть добавлено перед каждым символом и использовать пробел в качестве «разделителя полей» и избегать пустой FS:

 sed -e 's/./ &/g' < "$file" | awk ' {for(i=1;i<=cc;i++){if($i==""){$i=" "};r[i]=r[i]sep$i;};sep=""}; END{for(i=1;i<=cc;i++)print(r[i])} ' cc="$countcols" для sed -e 's/./ &/g' < "$file" | awk ' {for(i=1;i<=cc;i++){if($i==""){$i=" "};r[i]=r[i]sep$i;};sep=""}; END{for(i=1;i<=cc;i++)print(r[i])} ' cc="$countcols" 

Прокомментируйте линию sed для новых awks.

Вот решение с cut и paste . Поскольку у вас нет разделителя, такого как пространство или табулятор, ему нужно некоторое исправление с sed :

 for COL in {1..5}; do cut -c $COL < infile | paste -s -d_ ; done | sed -e 's/__/_ /g' -e 's/_//g' 

Здесь разбито в многострочном:

 for COL in {1..5}; do cut -c $COL < infile | paste -s -d_ done | sed -e 's/__/_ /g' -e 's/_//g' 

Результат первой части выглядит так:

 for COL in {1..5}; do cut -c $COL < infile | paste -s -d_ ; done a_f_k_o b_g_l_p c_h_m_q d_i_n_r e_j__s 

Досадно, что вам нужно знать, сколько столбцов есть до начала.

Linux и Unix - лучшая ОС в мире.