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 

3 Answers 3

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.
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

1
  • Thanks for improvement on the paste solution ... cheers Commented Sep 1, 2019 at 11:01
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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.