Преобразовать текстовый файл в строку с разделителями-запятыми - PullRequest
0 голосов
/ 01 ноября 2018

Я, кажется, не могу найти вопрос, который соответствует именно этой проблеме.

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

Введите:

one
two
three

Выход:

one,two,three

Я использую эту команду:

csv_string=$(tr '\n' ',' < file | sed 's/,$//')

Есть ли более эффективный способ сделать это?

Ответы [ 5 ]

0 голосов
/ 03 ноября 2018

Протестировано четыре подхода на Linux-коробке - Bash only , paste , awk , Perl , а также tr | sed подход, показанный в вопросе:

#!/bin/bash

# generate test data
seq 1 10000 > test.file

times=${1:-50}

printf '%s\n' "Testing paste solution"
time {
    for ((i=0; i < times; i++)); do
      csv_string=$(paste -sd, test.file)
    done
}

printf -- '----\n%s\n' "Testing pure Bash solution"
time {
    for ((i=0; i < times; i++)); do
      csv_string=$(<test.file)          # read file into variable
      csv_string=${csv_string//$'\n'/,} # replace \n with ,
      csv_string=${csv_strings%,}       # remove trailing comma
    done
}

printf -- '----\n%s\n' "Testing Awk solution"
time {
    for ((i=0; i < times; i++)); do
      csv_string=$(awk '{$1=$1}1' FS='\n' OFS=',' RS= test.file)
    done
}

printf -- '----\n%s\n' "Testing Perl solution"
time {
    for ((i=0; i < times; i++)); do
      csv_string=$(perl -ne '{ chomp; $_="$_," if not eof; printf("%s",$_) }' test.file)
    done
}

printf -- '----\n%s\n' "Testing tr | sed solution"
time {
    for ((i=0; i < times; i++)); do
      csv_string=$(tr '\n' ',' < test.file | sed 's/,$//')
    done
}

Удивительно, но решение только для Bash работает довольно плохо. paste идет сверху, затем следуют tr | sed, Awk и perl:

Testing paste solution

real    0m0.109s
user    0m0.052s
sys 0m0.075s
----
Testing pure Bash solution

real    1m57.777s
user    1m57.113s
sys 0m0.341s
----
Testing Awk solution

real    0m0.221s
user    0m0.152s
sys 0m0.077s
----
Testing Perl solution

real    0m0.424s
user    0m0.388s
sys 0m0.080s
----
Testing tr | sed solution

real    0m0.162s
user    0m0.092s
sys 0m0.141s

По некоторым причинам csv_string=${csv_string//$'\n'/,} зависает на MacOS Mojave под управлением Bash 4.4.23.


Похожие сообщения:

0 голосов
/ 01 ноября 2018

с однострочником Perl:

$ cat csv_2_text
one
two
three
$ perl -ne '{ chomp; push(@lines,$_) } END { $x=join(",",@lines);  print "$x" }' csv_2_text
one,two,three

$ perl -ne ' { chomp; $_="$_," if not eof ;printf("%s",$_) } ' csv_2_text
one,two,three
$

От @ codeforester

$ perl -ne 'BEGIN { my $delim = "" } { chomp; printf("%s%s", $delim, $_); $delim="," } END { printf("\n") }' csv_2_text
one,two,three
$
0 голосов
/ 01 ноября 2018

Обычная команда для этого: paste

csv_string=$(paste -sd, file.txt)
0 голосов
/ 01 ноября 2018

Одним из способов с Awk будет сброс RS и обработка записей как разделенных пустыми строками. Это будет обрабатывать слова с пробелами и форматировать их в формате CSV, как и ожидалось.

awk '{$1=$1}1' FS='\n' OFS=',' RS= file

{$1=$1} - это способ восстановления полей в каждой строке ($0) файла на основе изменений в разделителях полей (FS/OFS) и / или записи (RS/ORS). Трейлинг 1 должен печатать каждую строку с изменениями, выполненными внутри {..}.

0 голосов
/ 01 ноября 2018

Вы можете сделать это полностью с помощью операторов расширения параметров bash вместо использования tr и sed.

csv_string=$(<file)               # read file into variable
csv_string=${csv_string//$'\n'/,} # replace \n with ,
csv_string=${csv_string%,}        # remove trailing comma
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...