-2

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?

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

0
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
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
4
  • 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 stackoverflow.com/questions/19075671/….
    – Ed Morton
    Sep 15 '21 at 13:57
  • haha, I went straight to paste/yes first too! 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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.