-1

I have two files. One contains several columns and rows, while the other one only contains one value:

  • file1:
    abc def
    ghi jkl
    
  • file2:
    hello
    

I want to add another column to file1 that always contains the value found in file2. So, the output should look like this:

abc def hello
ghi jkl hello

Can anyone help me do that?

Braiam
  • 35,991

5 Answers5

4

You can get the last line of the file with tail, and then pass that as an external variable to awk, telling awk to print each line and the variable:

$ awk -v s="$(tail -n1 file2)" '{print $0,s}' file1
abc def hello
ghi jkl hello

Note that this assumes that i) you want the last line of the file2; if that's not the case, you can replace tail -n1 file with cat "$file", and ii) that file2 doesn't contain escape sequences (see How do I use shell variables in an awk script? on SO).

ilkkachu
  • 138,973
terdon
  • 242,166
3

This will work no matter what the string is in file2:

$ awk 'NR==FNR{x=$0; next} {print $0, x}' file2 file1
abc def hello
ghi jkl hello

or if you prefer and if the string in file2 can't contain backslashes (-v interprets escape sequences):

$ awk -v x="$(< file2)" '{print $0, x}' file1
abc def hello
ghi jkl hello

Here's the difference:

$ cat file2
hello\there

$ awk 'NR==FNR{x=$0; next} {print $0, x}' file2 file1 abc def hello\there ghi jkl hello\there

$ awk -v x=$(< file2) '{print $0, x}' file1 abc def hello here ghi jkl hello here

Ed Morton
  • 31,617
2

Since it's a constant string you're adding there, using sed comes to mind, with the caveat that the string to add is embedded on sed's command line, so anything processed specially by sed will not be taken as-is. E.g. a / would taken to terminate the s/// command, and & would be replaced by the pattern part.

$ str=$(cat file2)
$ sed -e "s/\$/ $str/" file1
abc def hello
ghi jkl hello

See e.g. discussion in: Replace the first occurence of a pattern in a file that may contain a slash

Similarly with awk, though this also isn't as content-agnostic as one might think, since for strings set with -v, awk processes C-style backslash escapes, so the string foo\tbar would turn into foo[tab]bar, which may or may not be what you want.

$ str=$(cat file2)
$ awk -v str="$str" '{print $0 " " str}' < file1
abc def hello
ghi jkl hello

See e.g.: Use a shell variable in awk


Or, I guess you could use other tools too, though this turned out a bit Rube Goldberg-esque. I don't know what led me into making this up:

$ paste file1 <( yes "$(cat file2)" ) | head -n "$(wc -l < file1)"
abc def hello
ghi jkl hello
ilkkachu
  • 138,973
  • 1
    Regarding "arbitrary values..." - file2 couldn't contain escapes sequences in the awk command since -v interprets those, e.g. try it if file2 contained hello\there. You'd have to populate the awk variable str from ENVIRON or ARGV for it to be taken literally, see https://stackoverflow.com/questions/19075671/how-do-i-use-shell-variables-in-an-awk-script. – Ed Morton Sep 15 '21 at 13:57
  • haha, I went straight to paste/yes first too! – glenn jackman Sep 15 '21 at 14:03
  • 1
    @EdMorton, oh, right. That was the reason using envvars was a thing. I always forget that, thanks for the reminder. – ilkkachu Sep 15 '21 at 14:42
  • FWIW my first thought was seq + wc + paste but I didn't complete the thought as it started looking like it might get messy :-). I never think of yes. – Ed Morton Sep 15 '21 at 14:58
0

Using Raku (formerly known as Perl_6)

raku -e 'my $str="/path/to/file2".IO.lines(1); .subst(/(^.*$)/, {$0,$str}).put for lines;' file1

Briefly, the first (and presumably only) line of file2 is read in to the variable $str, then file1 is analyzed linewise, subst-ituting (really, appending) $str to the end of each line, even blank lines. To change the behavior to only adding "hello" to the end of a character-containing line, change (^.*$) to (^.+$).

Sample Input:

  • file1:
    abc def
    ghi jkl
    
  • file2:
    hello
    

Sample Output:

abc def hello
ghi jkl hello

Having Raku handle both file1 and file2 input (instead of passage through a shell variable) should obviate a number of concerns regarding proper escaping of input.

https://docs.raku.org/routine/subst
https://www.raku.org

jubilatious1
  • 3,195
  • 8
  • 17
0

We can do as shown and not have to worry about escaping any characters:

$ sed rfile2 file1 | sed 'N;s/\n/ /'
abc def hello
ghi jkl hello
guest_7
  • 5,728
  • 1
  • 7
  • 13