Hello, forum :)

Does anyone know a c++ code that performs the same actions as a "tee" command does in linux? Basically what the tee command does is read an input from an input stream and directs it to two places:
1) Displays the input stream on the screen
2) Saves the input stream to a specified file
The documentation for a tee command can be found here. In that example, the tee command performs one more action: word count. I am not so worried about implementing this into my code; I just want to be able to read in all the text files and display it on the screen as well as save it to another text file.

Any suggestions would be great.

Thanks.

Dani AI

Generated

correctly pointed to the standard <fstream> API for file I/O, and 's teestream idea is a clean way to duplicate an ostream to stdout plus a file. The following concise GNU-tool workflow shows how to build, run, and debug that kind of C++ solution on a typical Linux setup.

The implementation file can be saved (for example) as mytee.cpp and compiled with g++:

g++ -std=c++11 -O2 -Wall -Wextra -o mytee mytee.cpp

If the implementation is split across translation units, compile to object files and link:

g++ -std=c++11 -O2 -Wall -Wextra -c teestream.cpp
g++ -std=c++11 -O2 -Wall -Wextra -c main.cpp
g++ -o mytee teestream.o main.o

A minimal Makefile pattern:

CXX = g++
CXXFLAGS = -std=c++11 -O2 -Wall -Wextra

mytee: main.o teestream.o
<TAB>$(CXX) $(CXXFLAGS) -o $@ $^

%.o: %.cpp
<TAB>$(CXX) $(CXXFLAGS) -c $<

Execution and quick checks: supply the output filename as the first argument and feed input on stdin. Example invocations:

echo "hello" | ./mytee out.txt
./mytee out.txt < input.txt

Troubleshooting tips: ensure the program checks argc before using argv[1]; verify the file opened successfully (permissions and path); if templates are used (as in 's solution), keep template definitions in headers or the same translation unit to avoid linker problems; call explicit flushes or std::endl when immediate stdout visibility is required. Use gdb, valgrind, or strace to diagnose crashes, memory errors, or file/permission issues. If only shell behavior is required, the system tee utility already provides this without custom code.

Recommended Answers

All 3 Replies

Did you hear about <fstream> class from the standart library.

It defines some basic file input/output operations for binary and text files, but you have to give the file names to the program, there is no folder manipulating operations defined in this class.

Unix tee is a filter which reads from stdin and in addition to piping the input to stdout also copies it into a file.

In C++, we can generalize the idea to a reusable component. Create a user-defined ostream that can send its output to two output streams. tee is then just a special case; read input from stdin and send output to stdout and a std::ofstream.

#include <iostream>

template < typename CHAR_TYPE,
           typename TRAITS_TYPE = std::char_traits<CHAR_TYPE> >
struct basic_teebuf : public std::basic_streambuf< CHAR_TYPE, TRAITS_TYPE >
{
    typedef std::basic_streambuf< CHAR_TYPE, TRAITS_TYPE > streambuf_type ;
    typedef typename TRAITS_TYPE::int_type int_type ;

    basic_teebuf( streambuf_type* buff_a, streambuf_type* buff_b )
            : first(buff_a), second(buff_b) {}

    protected:
        virtual int_type overflow( int_type c )
        {
            const int_type eof = TRAITS_TYPE::eof() ;
            if( TRAITS_TYPE::eq_int_type( c, eof ) )
                return TRAITS_TYPE::not_eof(c) ;
            else
            {
                const CHAR_TYPE ch = TRAITS_TYPE::to_char_type(c) ;
                if( TRAITS_TYPE::eq_int_type( first->sputc(ch), eof ) ||
                    TRAITS_TYPE::eq_int_type( second->sputc(ch), eof ) )
                        return eof ;
                else return c ;
            }
        }

        virtual int sync()
        { return !first->pubsync() && !second->pubsync() ? 0 : -1 ; }

    private:
        streambuf_type* first ;
        streambuf_type* second ;
};

template < typename CHAR_TYPE,
           typename TRAITS_TYPE = std::char_traits<CHAR_TYPE> >
struct basic_teestream : public std::basic_ostream< CHAR_TYPE, TRAITS_TYPE >
{
    typedef std::basic_ostream< CHAR_TYPE, TRAITS_TYPE > stream_type ;
    typedef basic_teebuf< CHAR_TYPE, TRAITS_TYPE > streambuff_type ;

    basic_teestream( stream_type& first, stream_type& second )
         : stream_type( &stmbuf ), stmbuf( first.rdbuf(), second.rdbuf() ) {}

    private: streambuff_type stmbuf ;
};

typedef basic_teebuf<char> teebuf ;
typedef basic_teestream<char> teestream ;

A dumbed down (no error handling, parsing and processing of command line switches etc.) program to use a teestream to implement the tee command:

#include <fstream>

int main( int argc, const char** argv )
{
    std::ofstream file( argv[1] ) ;
    teestream teeout( std::cout, file ) ;
    teeout << std::cin.rdbuf() ;
}

use it this way:
compile > g++ -Wall -std=c++98 -pedantic -Werror -ominimaltee and run > cat *.cc | grep #include | wc -l | ./minimaltee count.txt

commented: You're sick. But in a good way :) +16

thanks!!

Okay, then now my next question is this: "How do I run this c++ code using GNU Tools? I've been reading about GNU Tools but it's not making much sense...thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.