2013-03-16 2 views
4

У меня есть данные положительных или отрицательных значений с плавающей запятой в одном столбце, который разделен двумя пустыми строками.Данные одного столбца для нескольких столбцов

1.0 
-2.0 


3.0 
4.0 


-5.0 
6.0 


-7.0 
8.0 

В Баш, что было бы лучшим способом, чтобы получить эти данные в несколько столбцов, так что конечный результат выглядит примерно так:

1.0 3.0 -5.0 -7.0 
-2.0 4.0 6.0 8.0 

В идеальном случае решение будет работать не только для чисел, но также и текст, разделенный аналогичным образом.

+0

Я думал о разделении данных на несколько массивов, а затем их объединять, но мои попытки прочитать файл в переменной, а затем разделить на что-то вроде '($ {FILE // \ n \ n /}) 'не были особенно успешными. – heuristicus

+0

Вот что я делаю ниже, скажите, хорошо ли это для вас. –

ответ

11

Как насчет:

$ grep -v '^\s*$' file | pr -ts" " --columns 4 
1.0 3.0 -5.0 -7.0 
-2.0 4.0 6.0 8.0 

grep используется для удаления пустых строк и pr для форматирования вывода.

+2

+1 для 'pr', но было бы здорово увидеть обобщенную версию. – cmbuckley

+1

'-s" "' может быть предпочтительнее '-w20'. Тем не менее, +1 –

0

Скажите, что ваши данные находятся в файле data.txt; вы можете попробовать:

a=($(< data.txt)) 
b(){ for((i=$1; i<${#a[*]}; i+=2)); do echo -n "${a[$i]} "; done; echo ;} 
b 0 
b 1 

Это, конечно, не самый лучший способ, но он работает!

1

Это больше, но более читаемым решение:

a=() b=() i=0 
while read line ; do 
    case $i in 
     0) a+=($line) ;; 
     1) b+=($line) ;; 
    esac 
    ((i++)) 
    if ((i == 4)); then i=0; fi 
done < data.txt 

echo ${a[*]} 
echo ${b[*]} 
+2

Обратите внимание, что вы можете добавить к массиву следующего вида: 'a + = (" $ line ")' –

+0

Очень приятно! спасибо, я обновлю. –

+1

Вы также можете заменить 'if ((i == 4)); то i = 0; fi' с '((i% = 4))'. И сочетается с предыдущей строкой: '((i = ++ i% 4))' –

0

Можно также попробовать "массировать" вход с xargs first

while read a b 
do 
    A+=($a) B+=($b) 
done < <(xargs -n2 < file) 

printf "%s\n" "${A[*]}" "${B[*]}" 

-

Или

while read a; read b; do 
    read; read; 
    A+=($a) B+=($b) 
done < file 

printf "%s\n" "${A[*]}" "${B[*]}" 
0

с помощью одного вызова AWK:

awk 'BEGIN{RS="\n\n\n"}{A=A " " $1;B=B " " $2}END{printf A "\n" B "\n"}' NewFile 

используя p osix оболочка только (с встроенными командами)

#!/bin/sh 
L="" 
R="" 
while read A && read B && read dummy && read dumtwo || [ "$A" ];do 
    L="$L $A" 
    R="$R $B" 
done < NewFile 
echo $L 
echo $R 

Примечание: вместо того, чтобы хранить переменные в строках $ L и $ R, вы можете использовать Баш массивы вместо используя L_ARRAY + = ("$ A") или так:

#!/bin/bash 
L=() 
R=() 
while read A && read B && read dummy && read dumtwo || [ "$A" ];do 
    L[${#L[@]}]=${A} 
    R[${#R[@]}]=${B} 
done < NewFile 
echo -e "${L[@]}\n${R[@]}" 

или используя SED (2 звонки)

L=`sed -n 1~4p NewFile` 
R=`sed -n 2~4p NewFile` 
echo $L 
echo $R 
2

Это может работать для вас (GNU SED):

sed -r '/./!d;$!N;2{h;d};G;s/^(.*)\n(.*)\n(.*)\n(.*)$/\3 \1\n\4 \2/;$!{h;d}' file 
  • /./!d если строка не содержит символ, удалите ее.
  • $!N Если строка не последняя, ​​добавьте новую строку и следующую строку в пространство шаблона (PS).
  • 2{h;d} для второй линии, скопируйте PS в пространство удержания (HS), а затем удалите его.
  • G для всех остальных линий присоединяйте HS к PS.
  • s/^(.*)\n(.*)\n(.*)\n(.*)$/\3 \1\n\4 \2/ Переустановите PS в том порядке, в котором это необходимо.
  • $!{h;d} для всей линии, за исключением последней копии PS для HS, а затем удалить PS. Это означает, что при встрече с последней строкой будет распечатано содержимое PS.
+0

Я впервые вижу эти проводные символы (опции) в sed. не могли бы вы объяснить, что это такое и что они делают. – Satish

Смежные вопросы