I have a file with lines, just like this:
A
B
C
I want to create a duplicate file in bash that contains each line merged with the copy of next line, like:
A;B
B;C
C;
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityI have a file with lines, just like this:
A
B
C
I want to create a duplicate file in bash that contains each line merged with the copy of next line, like:
A;B
B;C
C;
Using awk
:
awk 'prev{ print prev ";" $0 }
{ prev = $0 }
END { if (NR) print prev ";" }'
which with your input, gives
A;B
B;C
C;
Quick'n'dirty way (involves reading the file twice):
$ tail -n+2 file | paste -d';' file -
A;B
B;C
C;
paste
shortly after tail
so it will be in cache. Chances are it's going to be more efficient than sed
/awk
based solutions. One down side is it can't work on pipes.
May 2, 2019 at 12:36
$ sed 'x;G;s_\n_;_;1d;${p;x;s_$_;_;}' file
A;B
B;C
C;
What that sed
expression is doing:
x
: save the incoming line in hold space, and retrieve the previous oneG
: append the new line (from hold space) to the old ones_\n_;_
: replace line-break with a ;
.1d
: if this is the first line, delete it (don't print it) and advance to next${...;}
: if this is the last line...p
: first print the joined pairx
: retrieve the final lines_$_;_
: append final ;
Somewhat simpler sed
solution without hold space:
sed '$!N;y/\n/;/;p;y/;/\n/;D' file
$!N
to join next line (if any; the $!
is not needed with GNU sed
when not in POSIX mode)y/\n/;/
replace the newline with ;
p
rint the resulting liney/;/\n/
to change back to newline, so withD
you can get rid of the first line and continue with the next oneC
instead of C;
though on the OP's sample.
May 2, 2019 at 12:40
$!y/;/\n/
if the trailing ;
is required.
May 2, 2019 at 12:47
Same basic idea as the awk solution given by Torin:
$ perl -lne 'print "$last;$_" if defined $last; $last=$_;END{print "$last;" if $.}' file
A;B
B;C
C;
Or, if you're into the whole brevity thing:
$ perl -lne'$.>1?print"$l;$_":1;$l=$_}{print"$l;"if$.' file
A;B
B;C
C;
A Vim Solution
One can issue this command (credit to Conspicuous Compiler for suggesting this):
vim "+%s/\n\(.\+\)*/;\1\n\1" sample.txt
Alternatively and probably more customarily, start Vim and open the file and issue the ex command:
:%s/\n\(.\+\)*/;\1\n\1
Explanation:
Substitute the pattern:
\n
\(.+\)
, which composes the entire next line. The quantifier which follows, *
, just indicates that there can be zero or more matcheswith the following:
\1
\n
\1
.After:
vim '+*ThisReallylongCommand*'
May 2, 2019 at 22:15
;
characters?