Изменение перевода строки другим символом в bash

Вопрос интересен только в том случае, если разделители не обязательно находятся в одной строке. Это можно сделать несколькими способами (даже с sed ), но awk более гибок:

    #!/bin/sh
    awk '
    BEGIN { found = 0; }
    /xxx/ {
        if (!found) {
            found = 1;
            $0 = substr($0, index($0, "xxx") + 3);
        }
    }
    /yyy/ {
        if (found) {
            found = 2;
            $0 = substr($0, 0, index($0, "yyy") - 1);
        }
    }   
        { if (found) {
            print;
            if (found == 2)
                found = 0;
        }
    }
    '

Это легко проверяется для случаев, когда в строке находится не более одной подстроки, используя эти данные:

    this is xxx yy
    first
    second yyy

    xxx.x
    yyy

    xxx#yyy

и этот вывод (сценарий - «foo», данные - «foo.in "):

    $ cat foo.in|./foo
     yy
    first
    second 
    .x

    #

Принцип работы заключается в том, что входные данные находятся в $ 0 , а awk последовательно соответствует шаблонам xxx и yyy , позволяя более чем одной вещи изменять $ 0 на пути к последнему шагу, где он печатается.

Между прочим, этот пример не будет работать для

xxxxHelloyyyxxxWorldyyy

, поскольку он проверяет только первое совпадение . Сценарий Perl даст разные результаты, поскольку он использует жадное сопоставление, а не индекс / подстроку, который я использовал в примере с awk. Perl, конечно, может делать то же самое - с помощью сценария.

Awk (например, Perl) имеет свободный формат, поэтому команду можно выразить как что-то вроде

awk 'BEGIN{found=0;}/xxx/{if(!found){found=1;$0=substr($0,index($0, "xxx")+3);}}/yyy/{if(found){found=2;$0=substr($0,0,index($0,"yyy")-1);}}{ if(found){print;if(found==2)found=0;}}'

, но это делается редко, за исключением примера. Точно так же скрипты sed (строчно-ориентированные) могут быть объединены в одну строку с некоторыми ограничениями. Опять же, сложные сценарии в sed редко обрабатываются таким образом. Скорее, они рассматриваются как настоящие программы (см. пример ).

Дальнейшее повторное ading:

1
26.04.2019, 12:41
8 ответов

Используйтеtr:

$ <input.txt tr "\n" ","
8600,22007,93509,9984,22146,
0
27.01.2020, 23:11

Вы можете использоватьtr

tr '\n',

Это изменит каждый экземпляр \nна запятую, поэтому вам нужно исправить последний. Вот пример

cat >file.txt <<x
8600
22007
93509
9984
22146
x

tr '\n', <file.txt
8600,22007,93509,9984,22146,        # and the shell prompt follows immediately

tr '\n', <file.txt | sed 's/,$/\n/'
8600,22007,93509,9984,22146         # line is ended with newline

Обратите внимание, что такое использование sedне определено стандартом POSIX, который предполагает, что все строки завершаются символом новой строки. Вы можете исправить это, вставив awk 1в конвейер, потому что awkявно определено POSIX для добавления завершающей новой строки к последней строке, если она отсутствует:

tr '\n', <file.txt | awk 1 | sed 's/,$//'
8600,22007,93509,9984,22146         # line is ended with newline

Для быстрого исправления это было бы приемлемым (хотя pasteрешение, предлагаемое в другом месте, лучше ). Однако tr | awk | sed— уродливая комбинация, которую следует пересмотреть в производственном коде. Таким образом, мы можем закончить с этим:

awk 'NR>1 {printf ","}; {printf "%s", $0}; END {printf "\n"}' file.txt
2
27.01.2020, 23:11

одной командой paste:

paste -d, -s infile

-sдает команду печатать строки в s erial с -d,через запятую.

6
27.01.2020, 23:11

Если вы хотите сделать это в чистом Bash, вы можете:

ar=( $(<filename) )
( IFS=, echo "${ar[*]}" > filename )

Это создает массив, ar, с разделяемыми пробелами -словами filenameв качестве элементов, а затем распечатывает его с запятыми между элементами. Все они построены -на функциях Bash.

Если у вас странные символы (, например.*)в ваших строках данных это будет работать неправильно, но для ваших данных это работает.

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

tmp=$(printf '%s,' $(<filename))
printf '%s\n' "${tmp%,}" > filename

для того же эффекта.

0
27.01.2020, 23:11

Используя GNU sedи предполагая, что в среде нет POSIXLY_CORRECTпеременной или если она есть, то ввод состоит как минимум из двух строк:

sed ':a;N;$!ba;s/\n/,/g' input.txt

мы не можем заменить новую строку . Но мы можем сделать это, добавив всю строку, как указано выше.....

1
27.01.2020, 23:11

Метод 1:

perl -pe 's/\n/,/ unless eof' filename

выход

8600,22007,93509,9984,22146

Метод 2 (Использование Python)

#!/usr/bin/python
m=open('file.txt','r')
j=[]
for i in m:
    j.append(i.strip())
print ",".join(j)

выход

python i.py 
8600,22007,93509,9984,22146
0
27.01.2020, 23:11

С awk:

awk '$1=$1' RS= OFS=, infile
0
27.01.2020, 23:11

Вы можете сделать это преобразование несколькими способами, некоторые из них:

$ (head -n -1 - | tr \\n, ;cat -;) < inp

$ perl -lp -0777e 'chop;tr/\n/,/' inp

$ awk '$1=$1' FS="\n" RS= OFS=, inp

$ awk '{
     p = $0
    while ( getline > 0 ) p = p RS $0
     $0 = p
     gsub(/\n/, ",")
 }1' inp

POSIX -СЭД:

$ sed -e '
    :a
    ${s/\n/,/g;q;}
    N;ba
' inp

ГНУ -СЭД:

$ sed -e '
    $!{
        N
        s/^/\n/;D
    }
    y/\n/,/
'  inp


$ perl -0777 -pe 's/\n(?!\z)/,/g' inp

$ perl -lpe '$\ = eof ? $/ : ","' inp
0
27.01.2020, 23:11

Теги

Похожие вопросы