1

Let's say there are two files, "main" and "rename". The file "rename" has a few lines with names for appending on the alternate rows of file "main". (according to the position in the "rename")

I has been using paste for concatenating lines from different files, but I was stucked on this case.

Is there any other ways of doing this without using copy and paste? (Preferably with the command that can be readily used in Ubuntu Linux 18.04.)

file "main"

#
stars
#
twinkle
#
on
#
the
#
sky

file "rename"

yellow
white
green
red
blue

desired output

#yellow
stars
#white
twinkle
#green
on
#red
the
#blue
sky
web
  • 193
  • 11

3 Answers3

2

You can use Awk by processing both the files, by keeping one file contents in the system memory and other as we iterate over it.

awk 'FNR==NR{ words[NR]=$0; next}{ if ($0 ~ /^#/) $0 = $0 words[++idx];  print }' rename main

A brief explanation of how it works

  • The part FNR==NR{ words[NR]=$0; next} operates on the first file rename by indexing your file contents in the array words. NR is a special variable in Awk which tracks the current line number. So the array becomes something like words['1']="yellow", words['2']="white"
  • The part {..} after now works on the next file rename and if the line matches # we update the current line $0 by appending the element from the array created.
  • The print command prints the line with string appended after #, for those lines starting with it, and other lines as-is.
Inian
  • 12,472
  • 1
  • 35
  • 52
1

This is rather easily done with a single paste invocation

<main paste -d '\0\n' - rename -
#yellow
stars
#white
twinkle
#green
on
#red
the
#blue
sky

When multiple delimiters are used in the delimiter list passed to -d, paste uses these delimiters consecutively until they're exhausted and then starts over with them again. In the above command the two delimiters passed are \0 (empty string) and \n(newline). Standard input is pointed to the main file, which is then referenced within the command twice via the two -'s, all leading to a line of output to form by

  1. taking a line from main and
  2. adding to it an empty string
  3. taking the next line from rename and adding it to the above
  4. then adding a newline to the above
  5. finishing the cycle by adding a line from main

And so on

iruvar
  • 16,515
  • 8
  • 49
  • 81
0

Here is a method that uses paste. First to double-space the second file, so that interesting lines are in parallel. Second to paste those lines together using a value \0 or NUL, which essentially does not appear as whitespace. We can use a number of schemes to double-space the output, but paste is convenient (such as sed as noted, *for others see How can I double the newlines in an output stream ).

The display of the two original files suggests the alignment that double-spacing can accomplish. The paste of the two files using the default separator simply shows that alignment. The real answer is presented in two ways, a standard way using a temporary file, the second using process substitution.

Here is the script snippet:

FILE1=${1-data1}
shift
FILE2=${1-data2}
E="expected-output"

# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }

pl " Input $FILE1 and $FILE2, columnized to save visual space:"
paste $FILE1 $FILE2 | expand -30

pl " Expected output:"
cat $E

rm -f t0
pl " Results, paste with double-space $FILE2, default options:"
# sed '/^$/d;G' $FILE2 > t0
paste -d '\n' - /dev/null < $FILE2 > t0
paste $FILE1 t0

pl " Results with paste of NUL, \0:"
paste -d'\0' $FILE1 t0

pl " Results with paste, process substitution:"
paste -d'\0' $FILE1 <( sed '/^$/d;G' $FILE2 )

producing:

 Input data1 and data2, columnized to save visual space:
#                             yellow
stars                         white
#                             green
twinkle                       red
#                             blue
on                            
#                             
the                           
#                             
sky                           

-----
 Expected output:
#yellow
stars
#white
twinkle
#green
on
#red
the
#blue
sky

-----
 Results, paste with double-space data2, default options:
#       yellow
stars
#       white
twinkle
#       green
on
#       red
the
#       blue
sky

-----
 Results with paste of NUL, \0:
#yellow
stars
#white
twinkle
#green
on
#red
the
#blue
sky

-----
 Results with paste, process substitution:
#yellow
stars
#white
twinkle
#green
on
#red
the
#blue
sky

THis was done on a system like:

OS, ker|rel, machine: Linux, 3.16.0-7-amd64, x86_64
Distribution        : Debian 8.11 (jessie) 
bash GNU bash 4.3.30
paste (GNU coreutils) 8.23

cheers, drl

drl
  • 838
  • 7
  • 8