diff --git a/cmdline/CTACmdMain.cpp b/cmdline/CTACmdMain.cpp
index 92b88e89199312730fbbdde2b895b3f5e6c9b1aa..0d731be96975eb381022ce22d4e7aed81f26a7cc 100644
--- a/cmdline/CTACmdMain.cpp
+++ b/cmdline/CTACmdMain.cpp
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdexcept>
+#include <xrootd/XrdCl/XrdClFile.hh>
 
 /**
  * Returns true if --stderr is on the command-line.
@@ -119,64 +120,70 @@ std::string formatCommandPath(const int argc, const char **argv) {
  * @return the return code
  */
 int sendCommand(const int argc, const char **argv) {
-  
+  int rc = 0;
   const bool writeToStderr = stderrIsOnTheCmdLine(argc, argv);
-  int p[2];
-  pipe(p); //Pipe to redirect std::out
-  int saved_stdout = dup(STDOUT_FILENO); //Saving std::out for later usage (re-redirection)
-  dup2(p[1], STDOUT_FILENO); //Do the actual redirection
-  close(p[1]); //Closing the write side of the pipe (replaced by std::out)
-  long flags = fcntl(p[0], F_GETFL);
-  flags |= O_NONBLOCK; //Setting fd as a NONBLOCKING one so that read returns zero when data is finished
-  fcntl(p[0], F_SETFL, flags);
-  //std::out is now redirected to p[0]
-  
-  XrdCl::PropertyList properties;
-  properties.Set("source", formatCommandPath(argc, argv));
-  properties.Set("target", "-"); //destination is stdout
-  XrdCl::PropertyList results;
-  XrdCl::CopyProcess copyProcess;
-  
-  //ConnectionWindow timeout
-  XrdCl::Env *env = XrdCl::DefaultEnv::GetEnv();
-  env->PutInt("ConnectionWindow", 3); //timeout in 3 secs if frontend server does not respond
-  
-  XrdCl::XRootDStatus status = copyProcess.AddJob(properties, &results);
-  if(!status.IsOK())
+  const std::string cmdPath = formatCommandPath(argc, argv);
+  XrdCl::File xrootFile;
+
+  // Open the xroot file reprsenting the execution of the command
   {
-    throw std::runtime_error(status.ToStr());
+    const XrdCl::XRootDStatus openStatus = xrootFile.Open(cmdPath, XrdCl::OpenFlags::Read);
+    if(!openStatus.IsOK()) {
+      throw std::runtime_error(std::string("Failed to open ") + cmdPath + ": " + openStatus.GetErrorMessage());
+    }
   }
-  
-  status = copyProcess.Prepare();
-  if(!status.IsOK())
+
+  // The cta frontend return code is the first char of the answer
   {
-    throw std::runtime_error(status.ToStr());
+    uint64_t readOffset = 0;
+    uint32_t bytesRead = 0;
+    char rc_char = '0';
+    const XrdCl::XRootDStatus readStatus = xrootFile.Read(readOffset, 1, &rc_char, bytesRead);
+    if(!readStatus.IsOK()) {
+      throw std::runtime_error(std::string("Failed to read first byte from ") + cmdPath + ": " +
+        readStatus.GetErrorMessage());
+    }
+    if(bytesRead != 1) {
+      throw std::runtime_error(std::string("Failed to read first byte from ") + cmdPath +
+        ": Expected to read exactly 1 byte, actually read " + std::to_string(bytesRead) + " bytes");
+    }
+    rc = rc_char - '0';
   }
-  
-  XrdCl::CopyProgressHandler copyProgressHandler;
-  status = copyProcess.Run(&copyProgressHandler);
-  if(!status.IsOK())
+
+  // Read and print the command result
   {
-    throw std::runtime_error(status.ToStr());
+    uint64_t readOffset = 1; // The first character at offset 0 has already been read
+    uint32_t bytesRead = 0;
+    do {
+      bytesRead = 0;
+      char buf[1024];
+      memset(buf, 0, sizeof(buf));
+      const XrdCl::XRootDStatus readStatus = xrootFile.Read(readOffset, sizeof(buf - 1), buf, bytesRead);
+      if(!readStatus.IsOK()) {
+        //throw std::runtime_error(std::string("Failed to read ") + cmdPath + ": " + readStatus.GetErrorMessage());
+        throw std::runtime_error(std::string("Failed to read ") + cmdPath + ": " + readStatus.ToString());
+      }
+
+      if(bytesRead > 0) {
+        std::cout << buf;
+
+        if(writeToStderr) {
+          std::cerr<<buf;
+        }
+      }
+
+      readOffset += bytesRead;
+    } while(bytesRead > 0);
   }
-  
-  dup2(saved_stdout, STDOUT_FILENO); //re-redirecting std::out to the original (everything we want is in the pipe by now)
-  
-  char rc_char = '0';
-  read(p[0], &rc_char, 1); //The cta frontend return code is the first char of the answer
-  int rc = rc_char - '0';
-  char buf[1024];
-  bzero(buf, sizeof(buf));
-  while(read(p[0], buf, sizeof(buf)-1)>0) { //read the rest of the answer and pipe it to std::err
-    buf[sizeof(buf)-1]=0;
-    std::cout<<buf;
-    if(writeToStderr) {
-      std::cerr<<buf;
+
+  // Close the xroot file reprsenting the execution of the command
+  {
+    const XrdCl::XRootDStatus closeStatus = xrootFile.Close();
+    if(!closeStatus.IsOK()) {
+      throw std::runtime_error(std::string("Failed to close ") + cmdPath + ": " + closeStatus.GetErrorMessage());
     }
-    bzero(buf, sizeof(buf));
   }
-  close(p[0]);
-  
+
   return rc;
 }