Village
Village

Reputation: 24413

How to replace a match with an entire file in BASH?

I have a line like this:

INPUT file1

How can I get bash to read that line and directly copy in the contents of "file1.txt" in place of that line? Or if it sees: INPUT file2 on a line, put in `file2.txt" etc.

The best I can do is a lot of tr commands, to paste the file together, but that seems an overly complicated solution.

'sed' also replaces lines with strings, but I don't know how to input the entire content of a file, which can be hundreds of lines into the replacement.

Upvotes: 0

Views: 97

Answers (5)

Ivan
Ivan

Reputation: 7287

Sed solution similar to awk given erlier:

$ cat f 
test1

INPUT f1

test2

INPUT f2

test3

$ cat f1
new string 1

$ cat f2
new string 2

$ sed 's/INPUT \(.*\)/cat \1/e' f
test1

new string 1

test2

new string 2

test3

Bash variant

while read -r line; do
    [[ $line =~ INPUT.* ]] && { tmp=($BASH_REMATCH); cat ${tmp[1]}; } || echo $line
done < f

Upvotes: 0

Fonic
Fonic

Reputation: 2955

If you want to do this in pure Bash, here's an example:

#!/usr/bin/env bash

if (( $# < 1 )); then
    echo "Usage: ${0##*/} FILE..."
    exit 2
fi

for file; do
    readarray -t lines < "${file}"
    for line in "${lines[@]}"; do
        if [[ "${line}" == "INPUT "* ]]; then
            cat "${line#"INPUT "}"
            continue
        fi
        echo "${line}"
    done > "${file}"
done

Save to file and run like this: ./script.sh input.txt (where input.txt is a file containing text mixed with INPUT <file> statements).

Upvotes: 1

Paul Hodges
Paul Hodges

Reputation: 15348

Not the most efficient possible way, but as an exercise I made a file to edit named x and a couple of input sources named t1 & t2.

$: cat x
a
INPUT t2
b
INPUT t1
c
$: while read k f;do sed -ni "/$k $f/!p; /$k $f/r $f" x;done< <( grep INPUT x )
$: cat x
a

here's
 ==> t2

b

this
is
file ==> t1

c

Yes, the blank lines were in the INPUT files.
This will sed your base file repeatedly, though.
The awk solution given is better, as it only reads through it once.

Upvotes: 1

glenn jackman
glenn jackman

Reputation: 246942

A perl one-liner, using the CPAN module Path::Tiny

perl -MPath::Tiny -pe 's/INPUT (\w+)/path("$1.txt")->slurp/e' input_file

use perl -i -M... to edit the file in-place.

Upvotes: 1

William Pursell
William Pursell

Reputation: 212298

Seems pretty straightforward with awk. You may want to handle errors differently/more gracefully, but:

$ cat file1
Line 1 of file 1
$ cat file2
Line 1 of file 2
$ cat input
This is some content
INPUT file1
This is more content
INPUT file2
This file does not exist
INPUT file3
$ awk '$1=="INPUT" {system("cat " $2); next}1' input
This is some content
Line 1 of file 1
This is more content
Line 1 of file 2
This file does not exist
cat: file3: No such file or directory

Upvotes: 4

Related Questions