Распечатать строку из 16 строк равномерно рядом (столбец) - PullRequest
1 голос
/ 26 февраля 2020

У меня есть файл с неизвестным количеством строк (но четным числом строк). Я хочу напечатать их рядом на основе общего количества строк в этом файле. Например, у меня есть файл с 16 строками, как показано ниже:

asdljsdbfajhsdbflakjsdff235
asjhbasdjbfajskdfasdbajsdx3
asjhbasdjbfajs23kdfb235ajds
asjhbasdjbfajskdfbaj456fd3v
asjhbasdjb6589fajskdfbaj235
asjhbasdjbfajs54kdfbaj2f879
asjhbasdjbfajskdfbajxdfgsdh
asjhbasdf3709ddjbfajskdfbaj
100
100
150
125
trh77rnv9vnd9dfnmdcnksosdmn
220
225
sdkjNSDfasd89asdg12asdf6asdf

Так что теперь я хочу напечатать их рядом. так как у них всего 16 строк, я пытаюсь получить результаты 8: 8, как показано ниже

asdljsdbfajhsdbflakjsdff235 100
asjhbasdjbfajskdfasdbajsdx3 100
asjhbasdjbfajs23kdfb235ajds 150
asjhbasdjbfajskdfbaj456fd3v 125
asjhbasdjb6589fajskdfbaj235 trh77rnv9vnd9dfnmdcnksosdmn
asjhbasdjbfajs54kdfbaj2f879 220
asjhbasdjbfajskdfbajxdfgsdh 225
asjhbasdf3709ddjbfajskdfbaj sdkjNSDfasd89asdg12asdf6asdf

команда вставки не работает для меня точно, (paste - - - - - - - -< file1) или команда awk, которую я использовал awk '{printf "%s" (NR%2==0?RS:FS),$1}' Примечание: количество строк в файле динамо c. Единственная известная вещь в моем сценарии - они всегда чётные.

Ответы [ 6 ]

2 голосов
/ 26 февраля 2020
$ pr -2t file

asdljsdbfajhsdbflakjsdff235         100
asjhbasdjbfajskdfasdbajsdx3         100
asjhbasdjbfajs23kdfb235ajds         150
asjhbasdjbfajskdfbaj456fd3v         125
asjhbasdjb6589fajskdfbaj235         trh77rnv9vnd9dfnmdcnksosdmn
asjhbasdjbfajs54kdfbaj2f879         220
asjhbasdjbfajskdfbajxdfgsdh         225
asjhbasdf3709ddjbfajskdfbaj         sdkjNSDfasd89asdg12asdf6asdf

, если вы хотите, чтобы между столбцами был только один пробел, измените на

$ pr -2ts' ' file
2 голосов
/ 26 февраля 2020

Если у вас есть память до sh всего файла ("max" ниже):

$ awk '{
    a[NR]=$0                 # hash all the records
}
END {                        # after hashing
    mid=int(NR/2)            # compute the midpoint, int in case NR is uneven
    for(i=1;i<=mid;i++)      # iterate from start to midpoint
        print a[i],a[mid+i]  # output
}' file

Если у вас есть память до sh половины файла (" mid "):

$ awk '
NR==FNR {                           # on 1st pass hash second half of records
    if(FNR>1) {                     # we dont need the 1st record ever
        a[FNR]=$0                   # hash record
        if(FNR%2)                   # if odd record
            delete a[int(FNR/2)+1]  # remove one from the past
    }
    next
}
FNR==1 {                            # on the start of 2nd pass
    if(NR%2==0)                     # if record count is uneven
        exit                        # exit as there is always even count of them
    offset=int((NR-1)/2)            # compute offset to the beginning of hash
}
FNR<=offset {                       # only process the 1st half of records
    print $0,a[offset+FNR]          # output one from file, one from hash
    next
}
{                                   # once 1st half of 2nd pass is finished
    exit                            # just exit
}' file file                        # notice filename twice

И, наконец, если у вас есть awk, скомпилированный в мозг червей (ie. Не так много памяти," min "):

$ awk '
NR==FNR {                                       # just get the NR of 1st pass
    next
}
FNR==1 {                                       
    mid=(NR-1)/2                                # get the midpoint
    file=FILENAME                               # filename for getline
    while(++i<=mid && (getline line < file)>0); # jump getline to mid
}
{
    if((getline line < file)>0)                 # getline read from mid+FNR
        print $0,line                           # output
}' file file                                    # notice filename twice

Стандартный отказ от ответственности по getline и контроль реальных ошибок не реализован.

Производительность:

I seq 1 100000000 > file и тестирование работы вышеуказанных решений. Вывод был > /dev/null, но запись в файл длилась около 2 с. max производительность настолько низкая, что отпечаток памяти составляет 88% от моих 16 ГБ, поэтому он мог поменяться местами. Ну, я убил все браузеры и сбрил 7 секунд в реальном времени max.

+------------------+-----------+-----------+
| which            |           |           |
|              min |       mid |       max |
+------------------+-----------+-----------+
| time             |           |           |
| real    1m7.027s | 1m30.146s | 0m48.405s |
| user    1m6.387s | 1m27.314  | 0m43.801s |
| sys     0m0.641s | 0m2.820s  | 0m4.505s  |
+------------------+-----------+-----------+
| mem              |           |           |
|             3 MB |    6.8 GB |   13.5 GB |
+------------------+-----------+-----------+

Обновление:

Я тестировал @DavidC.Rankin и @ EdMorton * 1034 Решения * и они работали, соответственно:

real    0m41.455s
user    0m39.086s
sys     0m2.369s

и

real    0m39.577s
user    0m37.037s
sys     0m2.541s

Печать Mem была примерно такой же, как у моего mid. Кажется, стоит использовать wc.

2 голосов
/ 26 февраля 2020

Вы также можете сделать это с помощью awk, просто сохранив первую половину строк в массиве, а затем конкатенируя вторую половину до конца, например,

awk -v nlines=$(wc -l < file) -v j=0 'FNR<=nlines/2{a[++i]=$0; next} j<i{print a[++j],$1}' file

Пример использования / Вывод

С вашими данными в file, затем

$ awk -v nlines=$(wc -l < file) -v j=0 'FNR<=nlines/2{a[++i]=$0; next} j<i{print a[++j],$1}' file
asdljsdbfajhsdbflakjsdff235 100
asjhbasdjbfajskdfasdbajsdx3 100
asjhbasdjbfajs23kdfb235ajds 150
asjhbasdjbfajskdfbaj456fd3v 125
asjhbasdjb6589fajskdfbaj235 trh77rnv9vnd9dfnmdcnksosdmn
asjhbasdjbfajs54kdfbaj2f879 220
asjhbasdjbfajskdfbajxdfgsdh 225
asjhbasdf3709ddjbfajskdfbaj sdkjNSDfasd89asdg12asdf6asdf
2 голосов
/ 26 февраля 2020

Извлеките первую половину файла и последнюю половину файла и объедините строки:

paste <(head -n $(($(wc -l <file.txt)/2)) file.txt) <(tail -n $(($(wc -l <file.txt)/2)) file.txt)

Вы можете использовать колонки утилита из autogen:

columns -c2 --by-columns file.txt

Вы можете использовать column , но количество столбцов вычисляется странным образом из числа столбцов вашего терминала. Таким образом, предполагая, что ваши строки имеют 28 символов, вы также можете:

column -c $((28*2+8)) file.txt
0 голосов
/ 26 февраля 2020

Вот мой пример использования bash shell wc(1) и ed(1)

#!/usr/bin/env bash

array=()
file=$1 
total=$(wc -l < "$file")
half=$(( total / 2 ))
plus1=$(( half + 1 ))

for ((m=1;m<=half;m++)); do
  array+=("${plus1}m$m" "${m}"'s/$/ /' "${m}"',+1j')
done

После всего этого, если вы просто хотите напечатать вывод в stdout. Добавьте строку ниже к сценарию.

printf '%s\n' "${array[@]}" ,p Q | ed -s "$file"

Если вы хотите записать изменения непосредственно в сам файл, используйте этот код вместо сценария.

printf '%s\n' "${array[@]}" w | ed -s "$file"

Вот пример.

printf '%s\n' {1..10} > file.txt

Теперь запускаем скрипт для этого файла.

./myscript file.txt

Вывод

1 6
2 7
3 8
4 9
5 10

Или используя функцию bash4 + mapfile aka readarray

Сохраните файл в массив с именем array.

mapfile -t array < file.txt

Разделите файлы.

left=("${array[@]::((${#array[@]} / 2))}") right=("${array[@]:((${#array[@]} / 2 ))}")

l oop и распечатайте их рядом

for i in "${!left[@]}"; do
  printf '%s %s\n' "${left[i]}" "${right[i]}"
done

То, что вы сказали The only known thing in my scenario is, they are even number all the time. Это решение должно сработать.

0 голосов
/ 26 февраля 2020

Я не хочу решать это, но на вашем месте:

wc -l file.txt 

дает количество строк

echo $(($(wc -l < file.txt)/2))

дает половину

head -n $(($(wc -l < file.txt)/2)) file.txt  > first.txt
tail -n $(($(wc -l < file.txt)/2)) file.txt  >  last.txt

создать файл с первой половиной и последней половиной исходного файла. Теперь вы можете объединить эти файлы вместе, как это было описано здесь .

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