Reputation: 1603
I am trying to concatenate the contents (a block of code) of a file called query.sql
in a README.md
document, that already contains some text. However, I would also like this block of code to be preceded by a heading "Model answer".
In other words, if my README.md
file was currently structured as
# Title
Some text here.
the new file should look like
# Title
Some text here.
## Model answer
```sql
Contents of query.sql
```
The subtitle ## Model answer
is currently not in any file, so the process should involve something like
cat "## Model answer\n\n```sql\n" query.sql "\n```" >> README.md
but cat
only works with sets of files, not files and strings. How could I achieve the desired result in BASH?
Upvotes: 4
Views: 5356
Reputation: 7348
You can read readme into a variable:
README=$(cat readme.md)
And the SQL file:
SQL=$(cat query.sql)
Combine them:
OUTPUT="$README
## Model answer
$SQL"
And echo that back to the file (double quotes needed for line breaks):
echo "$OUTPUT" > readme.md
Upvotes: 1
Reputation: 1884
In bash (as you have tagged it) you can do
cat <(echo -e '## Model answer\n\n```sql') query.sql <(echo -e '```\n') >> README.md
The <()
uses process substitution; the command in parentheses is run in a subshell and its output is inserted into the larger command line. This form allows you to run without stringing lots of commands together.
If you really want avoid running commands -- for speed's sake -- you can get fancier and do this:
cat <(echo -e '## Model answer\n\n```sql') query.sql - <<<'```'
This uses here strings instead of one command. The -
means use standard input as an input to cat, and the <<<'```'
at the end means send this string to standard input.
Finally the coup de grace. You can even do something like this; in your specific case it's a bit unwieldy but it demonstrates the concept:
$ cat /dev/fd/{4,5,6} query.sql /dev/fd/7 4<<<'### Model answer' 5<<<'' 6<<<'```sql' 7<<<'```'
### Model answer
```sql
Contents of query.sql
```
This means concatenate file descriptors 4, 5, and 6, query.sql, and file descriptor 7, while opening these file descriptors and sending the respective strings to them. (This doesn't require Linux [where /dev/fd
was developed] to work, bash interprets /dev/fd
itself and emulates it on systems that don't have it. This is why you can't do /dev/fd/[4-6]
.) I chose these file descriptors because 0-2 are reserved for stdin, stdout, and stderr, and 10 and above are reserved for bash, and I can't count correctly.
Upvotes: 2
Reputation: 3530
First you can printf
or echo -e
the required text and then cat
the file query.sql
after that. You can use &&
or ;
between the commands . If &&
is used then the second command will be executed only if the first command was successfull. ;
is treated as a command separator
{ printf "## Model answer\n\n \`\`\`sql" && cat query.sql && printf "\n\`\`\`"; } >> README.md
or
{ echo -e "## Model answer\n\n '''" ; cat query.sql ; echo -e "''' /n"; } >> README.md
Upvotes: 3