45

I have a simple bash function dividing two numbers:

echo "750/12.5" | bc

I'd like to take the output from bc and append /24 and pipe said result to another instance of bc.

Something like:

echo "750/12.5" | bc | echo $1 + "/24" | bc

Where $1 is the piped result.

P.S. I realize I could just do echo "750/12.5/24" | bc my question is more in regards to the appending of text to a pipe result.

5
  • 3
    echo $(echo "750/12.5" | bc )/24" | bc?
    – DopeGhoti
    Commented Apr 22, 2017 at 0:06
  • @DopeGhoti nice I hadn't considered that approach. Commented Apr 22, 2017 at 0:07
  • 2
    @DopeGhoti This should be an answer. It should be the accepted answer, that's the simplest and most natural way to do it. Commented Apr 22, 2017 at 21:38
  • 1
    @Gilles, thanks; that means something coming from you (:
    – DopeGhoti
    Commented Apr 24, 2017 at 1:55
  • worth noticing vipe as an interactive on-the-pipe vi session. Commented May 28, 2023 at 22:55

6 Answers 6

38

I achieved this using sed and replacing the end of the line:

echo "my text" | sed 's/$/ more text/'

Returns:

my text more text

Your example:

echo "750/12.5" | bc | sed 's/$/\/24/' | bc
2
  • 6
    This doesn't work for multiline text input. In my case, I wanted to append an extra line to multiline text and process it. Ended up using: (figlet my_text && echo "new line") | boxes Commented Jan 10, 2020 at 18:32
  • Hugo, you're a command line ninja w/this! Awesome man, this is great!
    – Gary
    Commented Jul 20, 2022 at 21:09
23

Alternative approach:

TL;DR: Use cat to concatenate with stdin (-) as an argument. Note that it'll newline-separate your concatenated streams; remove if undesired.

Unfortunately this approach is a bit cumbersome for your particular use case since bc fails if there's a newline in the middle of that expression:

$ echo "750/12.5" | bc | cat - <(echo "/24") | bc
60
(standard_in) 2: parse error

You can work around that by deleting the newline from the original bc result:

$ echo "750/12.5" | bc | tr -d '\n' | cat - <(echo "/24") | bc
2

However, I came upon this question by googling "bash append to pipe", and in my case I actually do want that newline between the concatenations. So for those here for the same reason, use | cat - <(...):

$ echo foo | cat - <(echo bar)
foo
bar
$ echo foo | cat - <(echo bar) | sort | cat - <(echo last_line)
bar
foo
last_line
$ echo foo | cat - <(echo bar) | sort | cat <(echo header) - <(echo last_line)
header
bar
foo
last_line
3
  • This is the (elegant and) correct answer.
    – user247243
    Commented Mar 27, 2023 at 22:42
  • How do you append with a content of a file? Commented Jun 27, 2023 at 11:30
  • instead of the first : echo "first part..." (which adds a newline), use printf "%s" "first part...." (or printf "first part..." if there are no % in it) which will not put a newline, and thus makes appending the following of the line of computation easier) Commented Sep 21, 2023 at 9:49
18

In the simplest of the options, this does append to the pipe stream:

$ echo "750/12.5" | { bc; echo "/24"; }
60
/24

However that has an unexpected newline, to avoid that you need to either use tr:

$ echo "750/12.5" | { bc | tr -d '\n' ; echo "/24"; }
60/24

Or, given the fact that a command expansion removes trailing newlines:

$ printf '%s' $( echo "750/12.5" | bc ); echo "/24"
60/24

But probably, the correct way should be similar to:

$ echo "$(echo "750/12.5" | bc )/24"
60/24

Which, to be used in bc, could be written as this:

$ bc <<<"$(bc <<<"750/12.5")/24"
2

Which, to get a reasonable floating number precision should be something like:

$ bc <<<"scale=10;$(bc <<<"scale=5;750/12.5")/24"
2.5000000000

Note the need of two scale, as there are two instances of bc.

Of course, one instance of bc needs only one scale:

$ bc <<<"scale=5;750/12.5/24"

In fact, what you should be thinking about is in terms of an string:

$ a=$(echo "750/12.5")        # capture first string.
$ echo "$a/24" | bc           # extend the string
2

The comment about scale from above is still valid here.

2
  • 1
    Simple??? Why not a simple command substitution? Commented Apr 22, 2017 at 21:38
  • 2
    @Gilles A {…} is simple. The answer walks toward showing the user a "command substitution" as the best solution. Read again.
    – user232326
    Commented Apr 22, 2017 at 23:52
6

Something like this seems to work using xargs:

$ echo "750/12.5" | bc |xargs -I{} echo "{}+20" |bc
80

Or even:

$ echo "750/12.5" | bc |echo "$(</dev/stdin)+20" |bc
80

And why not :

$ bc <<<20+$(bc <<<"750/12.5")
80
1
  • Why not? Because it's unnecessarily complicated. Use a command substitution. Commented Apr 22, 2017 at 21:39
2

You could use awk to insert/append anything to the pipe:

$ date | awk 'BEGIN{print "prefix line"} {print}  END{print "suffix  line"}'
prefix line
Mo 21. Aug 15:24:30 CEST 2023
suffix  line

where

  • date - is your input pipe (current date for example here)
  • BEGIN{print "prefix line"} - this block will insert output before main
  • {print} - prints input pipe's contents; one could do some processing here if needed
  • END{print "suffix line"} - this appends output after main

To do same in single line, just use printf:

$ date | awk 'BEGIN{printf("prefix line >> ")} {printf($0)}  END{printf(" << suffix  line")}'
prefix line >> Mo 21. Aug 15:32:08 CEST 2023 << suffix  line/upload/sc505enb/tmp>

$ echo "750/12.5" | bc | awk '{printf($0)}  END{printf("/24\n")}'
60/24
0
-1

another possible BASH way - create a helper function which processes the stdin with read command and then prints extra line(s):

$ function append_lines(){ local data; while read -r data; do echo -en "$data"; done; echo "$*"; }

$ date | append_lines " +suffice_;line1" " ++line2" "  +++line_3"
[Mon Aug 21 16:00:37 CEST 2023][ +suffice_;line1  ++line2   +++line_3]

$ echo "750/12.5" | bc | append_lines "/24" | bc
2

where

  • while read -r data; do echo -en "$data"; done; - just passes the stdin (pipe) through. remove the -en modifier to print separate input lines.
  • echo "$*"; - prints all arguments of append_lines() to stdout
1
  • would be nice to know why this solution was downgraded?
    – Fedor
    Commented Nov 2, 2023 at 11:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .