The Crystal Programming Language Forum

Problem to get output of system command called

Hello, I encountered a problem today.
I use backticks to call some linux command and as well execute a script, but when I do that, the output is only visible when my process is completely done. Can I fix that ?

The part of my code:

if userAgreement
                            matchingSoftwaresArray.each_with_index do |software, index|
                                file = File.open("ISM.task", "w")
                                file << "require \"./#{ISM::Default::Path::SoftwaresDirectory + software.name + "/" + software.version + "/" + software.version + ".cr"}\"\n"
                                file << "target = Target.new\n"
                                file << "target.download\n"
                                file << "target.check\n"
                                file << "target.extract\n"
                                file << "target.patch\n"
                                file << "target.prepare\n"
                                file << "target.configure\n"
                                file << "target.build\n"
                                file << "target.install\n"
                                file.close
                                Ism.notifyOfDownload(software)
                                puts `crystal ISM.task`
                            end
                        end

I talk about the line when I do puts crystal ISM.task

Yes, you can call Process.run directly and directly pipe the output of the sub process to STDOUT. The option for that is output: :inherit.

Backticks are just some fancy way for calling Process.run. You can check the implementation here and adapt it for your use case: crystal/process.cr at 6529d725a61ed0ff83f9d9efdd18bb7229c9cebc · crystal-lang/crystal · GitHub

Oh thanks you !

I done that:

Process.run("crystal",args: ["ISM.task"],output: :inherit)

Is it normal some part of the output isn’t shown directly ? Or maybe I done that bad I think.

In some part of my script ISM.task, I have some lines with “puts” and bacticks commands

You want it to output the output of crystal ISM.task while it is running?

Yes

If this can help you,the file ISM.task instance this class:
require “…/…/SoftwaresLibrairies”

class Target < ISM::Software

    def initialize
        super
        @information.loadInformationFile("./Softwares/Binutils-Pass1/2.37/Information.json")
    end

    def download
        puts `wget https://ftp.gnu.org/gnu/binutils/binutils-2.37.tar.xz`
        #`wget https://ftp.gnu.org/gnu/binutils/binutils-2.37.tar.sig`
    end
    
    def check
        #`gpg binutils-2.37.tar.xz.sig`
    end
    
    def extract
        `tar -xf binutils-2.37.tar.xz`
    end
    
    def patch
    end

    def prepare
        Dir.cd("binutils-2.37")
        Dir.mkdir("build")
        Dir.cd("build")
    end
    
    def configure
        #Probleme, variable Ism n'est pas disponible
        puts `../configure   --prefix=#{Ism.settings.toolsPath} \
                        --with-sysroot=#{Ism.settings.rootPath} \
                        --target=#{Ism.settings.target} \
                        --disable-nls \
                        --disable-werror`
    end
    
    def build
        puts `make #{Ism.settings.makeOptions}`
    end
    
    def install
        puts `make -j1 install`
    end
    
    def uninstall
    end

end

Is it possible I have some conflicts ?

Because for example I don’t have output when my class do this line: puts make #{Ism.settings.makeOptions}

But I have a puts instruction

There is a block version of Process.run that yields the output as it runs. See Process - Crystal 1.3.0-dev.

However, taking a step back, do you thinking using backticks to execute code like this is a good idea? Depending on how you intend on distrubting this project, if at all, it would of course require the end user to have all these development tools avabile. E.g. make, crystal, wget, etc. Wouldn’t it be better to implement these methods using Crystal itself versus dynamically creating another Crystal file and compiling/running it within this app?

During you was writing, I found the solution. The backticks are the problem for the output. If for every backticks I replace to a Process.run, I have all of the output.

For your suggestions, yes 100% it’s what I would like, but the problem for example, actually crystal (for wget) don’t have a library to download and follow redirection, because for example binutils have a lot of redirection for it sources.

I prefer me too to use a full crystal implementation. I hate that.

For make ? There is any make implementation ? I didn’t think about that. Good idea

But it’s not 100% possible for my project to use full compiled code, because my files who describe how to install a software need to be interpreted, I want to load it dynamically.

Or one solution I was thinking is to distribute my project compiled with all of the softwares implementations, and when some software are added, give the fulled project compiled with the new softwares, but I’m not sure it’s good idea.

But anyway, for when I call make or wget, if I can replace it, of course I want, but It’s not a “big problem”, I can come back later to rewrite this part, it’s not complicate.

My big question about that , is it possible my project can have the capacity to update himself ?

But I would like your opinion about that, it’s an interesting conversation :blush:

There is a problem for example for wget. I done a test to check

I made one file, it taks is to execute a simple second file and show the output.

The first file:

Process.run("crystal",args: ["Cmd.cr"],output: :inherit)

The second file (Cmd.cr):

Process.run("wget",args: ["https://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.xz"],output: :inherit)

If I run my first file, I don’t have any output from my wget command, why ???

The funny thing is, if I change the first and the second file just with backticks, I have the output …

I understand nothing :lying_face: