18 votes

I want to learn programming. What language should i pick to write cli apps for linux?

I'm interested in C or Go, but i'm open to ideas.

I have plenty of sh scripts i created to integrate my tools and system, so i have some experience and i don't want a scripting language like python.

My first plan is to learn the basics of the language and rewrite some of those scripts.

I think my first pick will be a script that uses ffmpeg to convert my flac files to mp3 or opus. I use sndconv -opus/-mp3 and it checks if there are flac files in the folder (i only have full albums), converts and puts in a folder named "$artist - $album".

My long term goal is to make a cli/tui music player like cmus.

UPDATE: i'm having plenty of success with Go right now. I just wrote a basic version of my music conversion script. It's just converting a music i pass as argument to mp3, but i'll keep working on it and adding functionality just to dip my toes in Go. It seems like a good language and i'm having fun!

Thanks for all the answers!

42 comments

  1. [18]
    Adys
    Link
    You're saying you don't want to learn python but in what you're describing, python is the best fit. It's a great beginner language, scales fantastically well to a career (unlike bash), can lead...

    You're saying you don't want to learn python but in what you're describing, python is the best fit. It's a great beginner language, scales fantastically well to a career (unlike bash), can lead you into a community tackling serious problems and with lots of opportunities in ML, AI etc.

    If you want to write a CLI app in Python, I recommend the Click library. It's beautiful to work with. Although your "first script" sounds like it's better suited as a bash script.

    24 votes
    1. [5]
      Grand0rbiter
      Link Parent
      The script i want to reimplement is just for learning. It already works well and it's not really needed. I'm not seeking a career in programming exactly. I like it more as a hobby and i think...

      The script i want to reimplement is just for learning. It already works well and it's not really needed.

      I'm not seeking a career in programming exactly. I like it more as a hobby and i think writing a music player like cmus in python would not be ideal. I particularly don't like the language for cli apps because i like these apps to be as lightweight and simple as possible.

      When i switched from ranger (python) to nnn (C) and lf (Go) (terminal file managers), the difference in performance was astonishing.

      But thanks for the response. I'll look more into python.

      1 vote
      1. [3]
        Nodja
        Link Parent
        I think you have the wrong perception about python's performance, it's tens of time slower than C, but unless you're processing massive amounts of data, the performance will be irrelevant to you....

        I think you have the wrong perception about python's performance, it's tens of time slower than C, but unless you're processing massive amounts of data, the performance will be irrelevant to you. The task you mentioned for example should have no perceptible difference between a C and a python version, but it's much easier to write in python than in C. Can you really tell the difference between something taking 10 microseconds and 100? When all you doing is passing messages around, python is perfectly suitable.

        That said, between python, go and C, there's really no wrong choice. Each language has it's pros and cons.

        10 votes
        1. [2]
          Grand0rbiter
          Link Parent
          I don't know, but ranger (python) takes a lot more time to show the contents of folders and to initialize than nnn (C) and lf (Go) even in my recent laptop. More so in a raspberry.

          I don't know, but ranger (python) takes a lot more time to show the contents of folders and to initialize than nnn (C) and lf (Go) even in my recent laptop. More so in a raspberry.

          2 votes
          1. spit-evil-olive-tips
            Link Parent
            There are many, many possible reasons for the difference in speed beyond language choice. You can write fast Python; you can also write slow C or Go.

            There are many, many possible reasons for the difference in speed beyond language choice. You can write fast Python; you can also write slow C or Go.

            9 votes
      2. Staross
        Link Parent
        You could try Nim, it's fast as C but writes more like python, but is also better designed (as far as I can tell): https://nim-lang.org/

        You could try Nim, it's fast as C but writes more like python, but is also better designed (as far as I can tell):

        https://nim-lang.org/

        7 votes
    2. [12]
      mrbig
      Link Parent
      I was convincing myself to learn Click, but they really don't recommend using it with Python 3.

      Click

      I was convincing myself to learn Click, but they really don't recommend using it with Python 3.

      1. onyxleopard
        Link Parent
        I find argparse (which is now in the standard library since Python 3.2) to be very nice for writing CLI drivers. #!/usr/bin/env python3 import sys from os import get_terminal_size from operator...

        I find argparse (which is now in the standard library since Python 3.2) to be very nice for writing CLI drivers.

        #!/usr/bin/env python3
        
        import sys
        
        from os import get_terminal_size
        from operator import methodcaller
        
        """This is a simple demonstration of an argparse-based CLI driver for printing
        stylized text."""
        
        class String(str):
            """A string that can be styled"""
            def __init__(self, s):
                super(String, self).__init__()
            
            def spongebob(self):
                return ''.join(
                    [str.lower,str.upper][i%2](c)
                    for (i, c) in enumerate(self)
                )
        
        def main(
            message,
            repeat=1,
            alignment='<',
            spacer=' ',
            width=0,
            style='upper',
            reverse=False,
        ):
            if reverse:
                message = ''.join(reversed(message))
            for _ in range(repeat):
                fstring = f'{{:{spacer}{alignment}{width}}}'
                print((fstring.format(methodcaller(style)(String(message)))))
        
        if __name__ == '__main__':
            import argparse
            parser = argparse.ArgumentParser(
                formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                description=__doc__
            )
            parser.add_argument(
                'message',
                help='a message string to be styled'
            )
            parser.add_argument(
                '-n', '--repeat',
                type=int,
                default=1,
                help='number of times the message will be printed'
            )
            parser.add_argument(
                '-a', '--alignment',
                default='<',
                choices=('<', '^', '>'),
                help='alignment specifier'
            )
            parser.add_argument(
                '-p', '--spacer',
                default=' ',
                help='spacer string'
            )
            parser.add_argument(
                '-s', '--style',
                default='upper',
                choices=('upper', 'lower', 'spongebob'),
                help='how to style the message'
            )
            parser.add_argument(
                '-w', '--width',
                type=int,
                default=get_terminal_size().columns,
                help='output character width'
            )
            parser.add_argument(
                '-r', '--reverse',
                action='store_true',
                help='reverse the direction of the string'
            )
            args = parser.parse_args()
            main(
                args.message,
                repeat=args.repeat,
                alignment=args.alignment,
                spacer=args.spacer,
                width=args.width,
                style=args.style,
                reverse=args.reverse
            )
        

        Then use it like this:

        $ ./example.py -h                                                                                      
        usage: example.py [-h] [-n REPEAT] [-a {<,^,>}] [-p SPACER]
                          [-s {upper,lower,spongebob}] [-w WIDTH]
                          message
        
        positional arguments:
          message               a message string to be styled
        
        optional arguments:
          -h, --help            show this help message and exit
          -n REPEAT, --repeat REPEAT
                                number of times the message will be printed (default:
                                1)
          -a {<,^,>}, --alignment {<,^,>}
                                alignment specifier (default: <)
          -p SPACER, --spacer SPACER
                                spacer string (default: )
          -s {upper,lower,spongebob}, --style {upper,lower,spongebob}
                                how to style the message (default: upper)
          -w WIDTH, --width WIDTH
        $ ./example.py 'argparse is cool'                                                                      
        ARGPARSE IS COOL                                                                                           
        $ ./example.py 'argparse is cool' -s lower 
        argparse is cool
        $ ./example.py 'argparse is cool' -a '^' -r
                                                                      LOOC SI ESRAPGRA                                                               
        $ ./example.py 'argparse is cool' -p '_' -a '^' -s spongebob -n 5
        ______________________________________________________________aRgPaRsE Is cOoL_______________________________________________________________
        ______________________________________________________________aRgPaRsE Is cOoL_______________________________________________________________
        ______________________________________________________________aRgPaRsE Is cOoL_______________________________________________________________
        ______________________________________________________________aRgPaRsE Is cOoL_______________________________________________________________                                  
        $ ./example.py 'to the right' --spacer='.' --alignment='>' --style='upper'
        .................................................................................................................................TO THE RIGHT
        $ ./example.py 'argparse is cool' -n x
        usage: example.py [-h] [-n REPEAT] [-a {<,^,>}] [-p SPACER]
                          [-s {upper,lower,spongebob}] [-w WIDTH]
                          message
        example.py: error: argument -n/--repeat: invalid int value: 'x'
        
        4 votes
      2. [10]
        Adys
        Link Parent
        Why? Where did you see that?

        Why? Where did you see that?

        1 vote
        1. [9]
          mrbig
          Link Parent
          The docs.

          The docs.

          1. [8]
            Adys
            Link Parent
            You're not looking at the same docs as me. Did you end up on documentation for a massively outdated version? Click supports 3.x just fine. I've only ever used it with 3.x.

            You're not looking at the same docs as me. Did you end up on documentation for a massively outdated version? Click supports 3.x just fine. I've only ever used it with 3.x.

            6 votes
            1. [7]
              mrbig
              Link Parent
              I'm sorry, please help me understand what you mean by Python 3 support. Is this not valid documentation?

              I'm sorry, please help me understand what you mean by Python 3 support.

              Is this not valid documentation?

              1. [6]
                Adys
                Link Parent
                These issues affect any and all command line parsers in python 3, including the stdlib argparse, because of the way python treats sys.argv. Realistically they won't affect you unless your...

                These issues affect any and all command line parsers in python 3, including the stdlib argparse, because of the way python treats sys.argv. Realistically they won't affect you unless your arguments are super weird.

                3 votes
                1. [5]
                  mrbig
                  Link Parent
                  I see. I didn't get that impression from the docs. Further question: would you use Click to make a text editor? ;)

                  I see. I didn't get that impression from the docs. Further question: would you use Click to make a text editor? ;)

                  1. [4]
                    Adys
                    Link Parent
                    Not unless it's a text editor with a lot of command line arguments. Otherwise argparse works just fine. (argparse is a great library really, so much so that I even use it in JS:...

                    Not unless it's a text editor with a lot of command line arguments. Otherwise argparse works just fine. (argparse is a great library really, so much so that I even use it in JS: https://www.npmjs.com/package/argparse)

                    Click is super nice for argument-driven command line apps. For example, my battle.net authenticator BNA uses it: https://github.com/jleclanche/python-bna/blob/master/bin/bna

                    You can look at that file to get a feel for how simple click is. It allows me to very, very clearly and simply define behaviour for not just arguments but commands.

                    If I wanted to implement git in python, I'd use click for the CLI.

                    2 votes
                    1. mrbig
                      Link Parent
                      Cool. I’ll probably use blessings.

                      Cool. I’ll probably use blessings.

                    2. [2]
                      mrbig
                      Link Parent
                      What about a super-duper simple CLI task manager? Like even simpler than what people considered a simple nowadays? Even simpler than Steve Losh's t

                      What about a super-duper simple CLI task manager?

                      Like even simpler than what people considered a simple nowadays? Even simpler than Steve Losh's t

  2. [9]
    fifthecho
    Link
    I'll agree with Adys. Start with Python. Learn data structures. Learn control structures. Learn some algorithms. Learn how to build modules and functions. If for some reason you cannot get over...

    I'll agree with Adys.

    Start with Python. Learn data structures. Learn control structures. Learn some algorithms. Learn how to build modules and functions. If for some reason you cannot get over using Python, then use Ruby.

    Once you've got a hang of writing code in an interpreted language (and start interpreted because having a REPL makes life easier when you're getting the knack of things) and have written a moderate number of useful applications in an interpreted language, then start trying to tackle a compiled language.

    For that, I'd lean more strongly towards Rust and Go over C because you'll get a lot of niceties around importing libraries, dependency management, and such which are a gigantic PITA in C.

    If you really, really want to get into C, then start with Rust. Rust is hard and will kick your butt, but learning how to write Rust well will make you write better C/C++ because you'll be thinking about memory and safety far earlier than C/C++ expects you to.

    13 votes
    1. teaearlgraycold
      Link Parent
      For Rust I recommend the docopt library. It will allow you to write your program's CLI interface as a help manual, and automatically parse out the required fields into a struct. Example from my...

      For Rust I recommend the docopt library. It will allow you to write your program's CLI interface as a help manual, and automatically parse out the required fields into a struct.

      Example from my BrainFuck JIT compiler:

      const USAGE: &'static str = "
      Fucker
      
      Usage:
        fucker [--jit] <program>
        fucker (-d | --debug) <program>
        fucker (-h | --help)
      
      Options:
        -h --help     Show this screen.
        -d --debug    Display intermediate language.
        --jit         JIT compile the program before running (x86-64 only).
      ";
      
      #[derive(Debug, Deserialize)]
      struct Args {
          arg_program: String,
          flag_debug: bool,
          flag_jit: bool,
      }
      
      fn main() {
          let args: Args = Docopt::new(USAGE)
              .and_then(|d| d.deserialize())
              .unwrap_or_else(|e| e.exit());
      
          // ...
      }
      

      source

      3 votes
    2. [5]
      moocow1452
      Link Parent
      I always had an easier time grocking Ruby over Python, but at the same time I heard it's kind of on the wane as a language with Python being more established and Kotlin/Go being the next gen...

      I always had an easier time grocking Ruby over Python, but at the same time I heard it's kind of on the wane as a language with Python being more established and Kotlin/Go being the next gen solutions. Should I just bite the bullet and focus on Python or something like Java if I ever wanted to be a serious developer or is Ruby still pretty established?

      1 vote
      1. fifthecho
        Link Parent
        Ruby is still pretty established. It's no longer the shiny new thing, but Rails is solid, Chef and Puppet still use a lot of Ruby, and anyone who uses GitHub pages is getting HTML from Jekyll....

        Ruby is still pretty established. It's no longer the shiny new thing, but Rails is solid, Chef and Puppet still use a lot of Ruby, and anyone who uses GitHub pages is getting HTML from Jekyll.

        Having bounced between Ruby and Python a bunch in the last 6-7 years, there's a lot of similarities between Ruby and Python 3. It can take me about an hour or two to remember the particular syntax, but it's not hard.

        So, if you spend a bunch of time learning Ruby because you like the syntax better, you won't be wasting your time. The concepts you'll pick up around data structures, functions, classes, and objects are easily transferrable to most any other language. As a bonus, even if you end up working in a Kotlin job, you'll always have Ruby in your pocket to bang out some automation code or toss up a simple Sinatra site.

        Personally? I love Ruby.

        3 votes
      2. [3]
        Akir
        Link Parent
        Go, sure, but is Kotlin really that popular outside of Android development? I love Java, but I'm not sure I would recommend anyone learn it today. It certainly doesn't have the halcyon glow of...

        ... Kotlin/Go being the next gen solutions.

        Go, sure, but is Kotlin really that popular outside of Android development?

        I love Java, but I'm not sure I would recommend anyone learn it today. It certainly doesn't have the halcyon glow of universal enterprise endorsement anymore. Java is getting so little love today that it feels like it's not even the most popular JVM-targeting language anymore.

        1. [2]
          fifthecho
          Link Parent
          I honestly don't know. I just tossed it in because OP quoted Kotlin as something they were thinking about learning.

          I honestly don't know. I just tossed it in because OP quoted Kotlin as something they were thinking about learning.

          1. moocow1452
            Link Parent
            I just pay attention to buzzwords, honestly.

            I just pay attention to buzzwords, honestly.

    3. Adys
      Link Parent
      Fully agreed with your post.

      Fully agreed with your post.

      1 vote
  3. [3]
    ainar-g
    Link
    You say that you want to write CLI programmes but then you talk about scripts. Scripts are best written in, well, a scripting language. I would prefer POSIX Shell or Ruby, but Python is fine as...

    You say that you want to write CLI programmes but then you talk about scripts. Scripts are best written in, well, a scripting language. I would prefer POSIX Shell or Ruby, but Python is fine as well, I guess. When you'll want to write a CLI programme, I would recommend Go. Package flag from Go's standard library is seriously under-appreciated. For TUI, package github.com/gdamore/tcell is fairly popular these days, with lots of examples and stuff built on top of it.

    6 votes
    1. Grand0rbiter
      Link Parent
      I talked about rewriting one of my scripts in a programming language just as an exercise to learn the basics, a short term goal, but it's not necessary. That's why i didn't want to learn python. I...

      I talked about rewriting one of my scripts in a programming language just as an exercise to learn the basics, a short term goal, but it's not necessary.

      That's why i didn't want to learn python. I have plenty scripts already. One for converting music, i have a bulkrename script to open filenames in $EDITOR in a list so i can edit the names, save and it will rename the files, a status bar using lemonbar and a simple password manager.

      The end goal is to make a music player similar to cmus.

      I'm gonna look at tcell. Thanks!

      3 votes
    2. Grand0rbiter
      Link Parent
      I'm already using the flag package for command line flags and it's really nice and straightforward.

      I'm already using the flag package for command line flags and it's really nice and straightforward.

      1 vote
  4. [2]
    stu2b50
    Link
    I'll agree with the other users. Python is perfectly adequate for CLI scripts. It even comes with a competent argument parsing library. And technically, it's actually typically smaller in file...

    I'll agree with the other users. Python is perfectly adequate for CLI scripts. It even comes with a competent argument parsing library. And technically, it's actually typically smaller in file size than a complete binary, since basically every distro comes with a python installation now, so you just provide the script.

    It is a worthwhile exercise at some point to do C, but only if you're serious about programming. You'll learn to love garbage collectors, and all the other pleasantries modern languages provide, that's for sure.

    If you're really dead set on "performance" (almost certainly you'll be bottlenecked by I/O in this case anyway, so it does not matter), Go is a good balance. Rust if you want C-like performance without clawing your eyes out in valgrind and gdb. C++ if you want C while still clawing your eyes out but at least having sane data structures and smart pointers. Java/C#/Kotlin in a similar niche to Go.

    5 votes
    1. Grand0rbiter
      Link Parent
      I know C a little because i programmed PIC microcontrollers to automate a ruler printing machine in the past. Thanks for the tips!

      I know C a little because i programmed PIC microcontrollers to automate a ruler printing machine in the past.

      Thanks for the tips!

      2 votes
  5. [3]
    moose
    Link
    I'm going to go against the grain and say that if you're trying to make a music player, one that's relatively small/uncomplicated go with bash. The reason I say this is if you want to be able to...

    I'm going to go against the grain and say that if you're trying to make a music player, one that's relatively small/uncomplicated go with bash. The reason I say this is if you want to be able to easily interact with your system, which it seems you want to, then by far bash is going to be the easiest. Sure it might not be as pretty as other languages but dang does it make it easy to create commands, run other commands, and interact with files. Python you will have to deal with a few layers of abstraction, while bash is WYSIWYG. If you want a more programming and less script related language though, I would recommend python, but beware that this could cause you to have to install a whole lot more dependencies than simply using bash, making it possibly harder to transfer over to other systems if you don't use a tool like pipenv.

    2 votes
    1. [2]
      Grand0rbiter
      Link Parent
      I think the problem will be creating a database with the music. I want something similar to cmus with a library showing artists and albums.

      I think the problem will be creating a database with the music. I want something similar to cmus with a library showing artists and albums.

      1. Crestwave
        Link Parent
        Bash has arrays and associative arrays. You can use them then store them in a file and source it.

        Bash has arrays and associative arrays. You can use them then store them in a file and source it.

        1 vote
  6. clone1
    Link
    I agree with everyone else about python, it's a real, serious business programming language. Google, reddit, and tildes all use it. The performance impact isn't really relevant for most desktop...

    I agree with everyone else about python, it's a real, serious business programming language. Google, reddit, and tildes all use it. The performance impact isn't really relevant for most desktop apps, but I'd also look into using mpd for your music player, it's really nice, and it has good libraries for c and python

    2 votes
  7. [2]
    Soptik
    Link
    Out of C, Go and Rust, start with Go. C is old language that is no longer widely used for any projects (unless you’re building a game, OS, or are sircmpwn), and even then C++ is more used. Those...

    Out of C, Go and Rust, start with Go.

    C is old language that is no longer widely used for any projects (unless you’re building a game, OS, or are sircmpwn), and even then C++ is more used. Those languages are old and unnecessarily complicated for a beginner. I advice you to stay away of them as much as you can. They are good if you want to mess with memory yourself, but you don’t want to do that while learning programming. And there are many nasty things that would just make you hate programming.

    Rust is great language and I love it, but I can’t recommend it to you. It’s simply too hard to use. It’s as performant as C and seeks to replace it - which it does, Mozilla is writing new parts of Firefox in Rust, Google and Microsoft announced they are looking for secure fast language as C replacement - which Rust is [todo: source]. It has all the benefits of C but none of the cons of messing with memory yourself (which leads to awful, almost undebugable bugs and security vulnerabilities (about 80% of all Windows sevurity vulnerabilities are because of memory issues [todo: source]). The big problem is that you can’t use it as normal language, it has many constructs that no other language has, and it’s very different from any other language ever created. While I love it, I don’t think it’s a good language for a beginner because of it’s difficulty.

    I don’t know anything about Go, but it should be nice and fast to learn. So maybe try it.

    2 votes
    1. Akir
      Link Parent
      Just one small detail; C is still very common in the embedded world. It's useful because it has a very small footprint and is fairly low-level. But then again, things are changing now that...

      Just one small detail; C is still very common in the embedded world. It's useful because it has a very small footprint and is fairly low-level.

      But then again, things are changing now that everything is IoT; so many things are just using an SoC with Linux running on it.

      1 vote
  8. weystrom
    Link
    Golang, easy to pick up, very robust.

    Golang, easy to pick up, very robust.

    2 votes
  9. cmccabe
    Link
    I have a CLI use case that I think brings up an interesting (albeit maybe niche) consideration for which language to choose: interactive tools for a multi-user Linux shell environment. A while...

    I have a CLI use case that I think brings up an interesting (albeit maybe niche) consideration for which language to choose: interactive tools for a multi-user Linux shell environment.

    A while back, I set up a little (tiny) shell-based social club at rawtext.club with the goal of it being a free playground for people who like to tinker with shell programming and Linux command line utilities. Well one of the things you would expect to do in a place like this is to write tools or games through which users can interact. But this becomes a challenge if users need to write data to central locations. What you need is a setuid program. And here's the problem: for security reasons, scripting languages usually cannot be run setuid. You need to use compiled binaries from langauges like C if you want to make them setuid. There are workarounds like kicking off a script from a setuid binary wrapper or running the script as a local UDS or other server, but these just add another layer of complexity.

    My strong preference is for something like Python for CLI tools, but go with a compiled langauge if you think you'll ever need to make your program setuid.

    2 votes
  10. [2]
    Apos
    Link
    Other than what other people have said, I would suggest C# or even JavaScript. Nowadays, I would argue that JavaScript is a better language than Python.

    Other than what other people have said, I would suggest C# or even JavaScript. Nowadays, I would argue that JavaScript is a better language than Python.

    1 vote
    1. Diff
      Link Parent
      Mm, JavaScript's improved lately but there's still a lot of features and functions that are still (necessarily) supported that almost encourage a mess of nested callback spaghetti. Even if...

      Mm, JavaScript's improved lately but there's still a lot of features and functions that are still (necessarily) supported that almost encourage a mess of nested callback spaghetti. Even if JavaScript might now be a better language (much faster, equivalent clean language features), its past baggage probably makes it a poor starting point for someone who needs to learn the basics of loops and switches and functions.

      1 vote