
Using Rust for 'Scripting' - deverton
http://www.chriskrycho.com/2016/using-rust-for-scripting.html
======
itsweller
This reads less as “Python style scripting in Rust” and more as “I like Rust,
also it’s cross-platform.”

Not that this is a bad thing, but it feels like a bit of a far cry from my
hacked together workflow of throw code in iPython and write out when I’m
happy. I don’t see anything here that makes Rust any more attractive than
whatever your multiplatform language of choice is for this use case scenario.

That being said, the code is concise and readable, and the article was a
short, pleasant read.

~~~
ekidd
I've been using Rust to build a relatively large cross-platform command-line
tool, and I've been genuinely impressed at how easy it is to get things to
work on Windows. The Rust standard libraries Just Work on Windows, and they
provide pathname handling, threads, environment variables, and a wealth of
other tools. Many third party libraries will build for Windows without any
problems as well.

I actually do think that Rust's type system helps a bit, because it forces me
to consider weird portability issues (such as the way Windows permits slightly
invalid Unicode, which Rust represents as OSString instead of String).

And of course, cross-compilation with MinGW is a real help. Sadly, OpenSSL
still poses a fair number of portability issues, since it's notoriously
difficult to link statically.

~~~
vvanders
Yup, as someone who's done x-platform C++(Windows/OSX/X360/PS3/etc) for a
large part of my career the cross platform support is incredibly well done.

Not having to deal with differences between MSVC, LLVM, GCC and other obscure
toolchains is a blessing.

~~~
pjmlp
This is one reason why I enjoyed using Java so much in the early days, even
without JIT.

The differences between MSVC, LLVM, GCC are nothing to worry about, compared
with the early days of C89 or C++ARM in the process of being standardized,
coupled with different levels of POSIX support.

------
fnovd
>Writing it in Rust means I can compile it and hand it to him, and he can run
it. And that’s it. As wonderful as they are, the fact that languages like
Python, Perl, Ruby, JavaScript, etc. require having the runtime bundled up
with them makes just shipping a tool a lot harder—especially on systems which
aren’t a Unix derivative and don’t have them installed by default.

I'm wondering what part of the _twelve step_ compilation process was found to
be easier than simply installing Python on the target machine?

Does the friend have any ability to audit the compiled binary before he runs
it? Can he make a small change when he wants to re-use part of the solution?

~~~
mistaken
Python scripts can also be compiled to an exe file, although I think that the
following batch one-liner is the best for this job:

    
    
      for /r startdir %%i in (*.cha) do ECHO ren "%%i" "%%~ni.txt"

~~~
Annatar
Yep, one liner crushes the problem because a shell script is the perfect tool
for the job!

~~~
detaro
EDIT: nvm, I can't read properly...

~~~
Gibheer
He doesn't need to package bash, as that one liner is for the windows shell.

------
drej
This topic is dear to me, I often deal with people without any software stacks
on their machines and strict IT limits on installing new things. If I were on
the same OS as the target user, I'd use pyinstaller. I've used it with very
few issues over the past year on many projects. Most of them included
Flask/Bottle and parts of numpy, it all worked like a charm. Cross compilation
in Python is a bit of an issue, I for one have not resolved it in a
satisfactory fashion (not saying it can't be done).

If one wants to be closer to the metal, Go's cross compilation works out of
the box, without all the LLVM/MSVC work that Rust requires (for now, that is).
As long as you use the standard library (and packages dependent on the
standard library), it will work right away. I've cross compiled Go from my Mac
for Windows users when I couldn't get my Python setup to do so, worked
perfectly.

(Sure, you can script easy things as shown in other comments, this is a bit
more general.)

~~~
pcwalton
> If one wants to be closer to the metal, Go's cross compilation works out of
> the box, without all the LLVM/MSVC work that Rust requires (for now, that
> is).

That's not "closer to the metal"; it's reinventing parts of the native
toolchain.

~~~
drej
Sorry, I meant closer to the metal relative to Python, not relative to Rust,
poor wording.

------
brandur
I love this idea. There's an implicit assumption that the reason scripting
languages are suitable for scripts is that they play fast and loose with type
systems, which allow enough shortcuts and escape hatches to be productive.

But that's only part of the story. Along with typing, scripting languages also
had the major advantage of being fast to bootstrap and run (`ruby script.rb`)
and were fully "batteries included" with good standard libraries.

These assumptions are certainly true, but they're much _more_ true when you're
comparing them against "old world" languages like C, C++, or even Java. All of
these require significant project scaffolding just to get running, and have
varying levels of useful built-in utilities (C has almost nothing, C++ has the
STL and maybe Boost if you're generous, and Java tried to have a useful core,
but missed the mark in a number of places like HTTP). In the case of C and
C++, complex build logic may also be required in the form of
autoconf/automake/make.

Newer compiled languages like Rust just don't have these issues anymore (I'd
also include Go, Crystal, and some others in the list). Project scaffolding is
built right into the language (Cargo) and the standard library is about as
complete as you can get (and probably better than the classical scripting
languages — all of Ruby/Python/Perl missed a good API for some things like
HTTP, which led to the rise of separate packages like Faraday/Requests/etc).
Anything that's not in the standard library is easily retrievable through
great package managers that are bundled in with the core language.

After you're over the initial learning curve of the language and standard
library, it's possible to be nearly as productive in something like Rust as
you can be in Python. As a bonus, you can also get reasonable reassurance that
your program is correct before you run it — and even without writing an
exhaustive test suite that exercises every line of code.

~~~
Spiritus
>[...] the standard library is about as complete as you can get (and probably
better than the classical scripting languages — all of Ruby/Python/Perl missed
a good API for some things like HTTP, which led to the rise of separate
packages like Faraday/Requests/etc)

What? Rust basically has no standard library. At least Python doesn't require
pulling in third-party libraries to do globbing, create a zip/tar, create a
tempfile or send/serve http. Hell, it doesn't even do command-line arguments
outside of manually parsing and iterating over the args vector.

~~~
elktea
it sort of does, though. Trying to use urllib2 is like pulling teeth

~~~
Spiritus
Which is why you use httplib[1] for sending HTTP requests.

    
    
        >>> import httplib, json
        >>> conn = httplib.HTTPConnection("httpbin.org")
        >>> conn.request("GET", "/get")
        >>> res = conn.getresponse()
        >>> print res.status, res.reason
        200 OK
        >>> data = json.load(res)
        >>> print data
        {u'origin': '0.0.0.0', ...}
        >>> conn.close()
    

[1]
[https://docs.python.org/2.7/library/httplib.html#examples](https://docs.python.org/2.7/library/httplib.html#examples)

------
gravypod
This is over engineering if I've ever seen it. For one this is a single line
bash script that would allow you to even handle drag and drop. Best user
experience.

Second, if you're going to over engineering just look for someone who has
already done that for you:
[http://www.den4b.com/products/renamer](http://www.den4b.com/products/renamer)

It's no use to engineer something that has been solved (unless you're
learning) if there are already better solutions. Even if it is an example a
better one should be used.

The moral of the story should he use the best tool for the job, don't shoe
horn a bad language for a into a solution, and also Google is usually the best
tool for every job.

~~~
kibwen
I don't think the author is really expecting people to go out and start
uninstalling Python to do all their scripting in Rust. Seems to me like he saw
this as an opportunity to show off the clap and glob crates, as well as write
a little documentation for how to cross-compile Rust from Mac to Windows.

------
dbattaglia
It's a shame the author didn't frame this article differently by strictly
focusing on how to cross compile a simple rust app on macOS and Windows. The
focus on "scripting" seems to have really brought out the negativity in people
here. I definitely learned something, I had no idea I could compile a Windows
binary from my Mac.

~~~
chriskrycho
The author here: I agree with your assessment. Apparently the scare quotes
didn't convey my intent: it's easy to do something (including cross-platform)
where I normally would have used a traditional scripting language, and the
portability is nice. ¯\\_(ツ)_/¯

~~~
jsjohnst
I agree that it was very useful, despite the issue with the topic of choice.
Thanks for writing it!

------
fold_left
As someone who only _very_ recently caught the Rust bug; seeing a reasonably
small, familiar example like this is really helpful. Thanks for sharing. Maybe
I can learn something by seeing if I can introduce threads/channels to the
renaming part of the script as an exercise.

For anyone else curious about Rust, my own learning spree was triggered after
reading the "A very brief intro to Rust" Slide Deck [1] by Ashley Williams
[2].

[1] [https://ashleygwilliams.github.io/a-very-brief-intro-to-
rust...](https://ashleygwilliams.github.io/a-very-brief-intro-to-rust/#1)

[2] [https://twitter.com/ag_dubs](https://twitter.com/ag_dubs)

------
0xmohit
One could also use Haskell [0] for scripting [1] using the turtle [2] library.

    
    
      turtle is a reimplementation of the Unix command line
      environment in Haskell so that you can use Haskell as both a
      shell and a scripting language.
    

[0] [https://www.haskell.org/](https://www.haskell.org/)

[1] [http://www.haskellforall.com/2015/01/use-haskell-for-
shell-s...](http://www.haskellforall.com/2015/01/use-haskell-for-shell-
scripting.html)

[2]
[http://hackage.haskell.org/package/turtle](http://hackage.haskell.org/package/turtle)

~~~
rtpg
If we're talking about alternatives, xonsh is also an excellent alternative
(Python + subprocess mode) [http://xon.sh/](http://xon.sh/)

------
oconnor663
For folks who want to do Bash-style shellouts and pipelines from Rust code,
I'm working on a library to make it easier:
[https://github.com/oconnor663/duct.rs](https://github.com/oconnor663/duct.rs)

------
StreamBright
I think the author wanted to write "Using Rust instead of 'Scripting'".
Perfectly makes sense. Nicer features, static types, compiled code, no runtime
on the host system, etc. I prefer OCaml over Python,Bash etc for CLI apps, for
the same reasons.

------
kibwen
I admit, as a longtime Rust user I don't often get around to using Rust for
scripting, probably because Python is available on all my personal machines
and I'm so accustomed to it. But after reading this article I'm immensely
impressed at how far Rust has come in the past few years WRT suitability for
scripting, I really need to take a look at the glob and clap crates.

Also, I'm _very_ excited to hear that LLD is apparently usable for linking on
Windows! It seems like we've been waiting for LLD since time immemorial. :)

------
bajsejohannes
I found myself doing the same just a few days ago when my local server
suddenly had a new ip address. I made a simple script to scan IP addresses in
the range:
[https://gist.github.com/johshoff/bed463ce8a122123e60bbc84bd1...](https://gist.github.com/johshoff/bed463ce8a122123e60bbc84bd1b1129)

There are probably faster ways, but none that I could think of a the time.

~~~
pritambaral
> There are probably faster ways, but none that I could think of a the time

For future reference, `nmap -p22 --open 192.168.1.*` does everything your rust
script currently does.

Nmap is THE tool for the job of network scans. IMO, it should be in the
toolbelt of every techie that deals with any sort of computer network.

------
ghola2k5
I know this isn't the point.. but I can't help myself... PowerShell:

gci c:\somedir -r -filter "*.ext1" | %{Move-Item $_.FullName -Dest
($_.DirectoryName + "\" \+ $_.BaseName + ".ext2")}

------
IshKebab
Nice to see how good Rust is for 'scripting'. I think Go would have been a
better choice from a purely technical point of view - it's easier to write,
and has even easier setup and cross-compilation than Rust. But I guess part of
the point of this was to practice Rust so fair enough!

------
subtenante
> As wonderful as they are, the fact that languages like Python, Perl, Ruby,
> JavaScript, etc. require having the runtime bundled up with them makes just
> shipping a tool a lot harder

Not true for js on Windows, though. Windows runs JScript natively (same
language as JavaScript, only a different name).

------
daholland
There's also this handy cargo plugin that helps for using Rust for
"scripting": [https://github.com/DanielKeep/cargo-
script](https://github.com/DanielKeep/cargo-script)

It's especially handy for a one-file solution.

------
MayeulC
While this can be seen as an interesting exercise, I can't help but feel that
rust isn't the best tool here.

First, there are a handful of existing tools, as other have pointed out (I
would personally go for AntRenamer).

Then, there are a few scripting languages already installed (admittedly maybe
not the best or most well-known). A quick Google search would probably have
given a result right away, since this is a pretty common scenario.

Lastly, I am a bit curious, why go with msvc and not mingw/clang ?

~~~
chriskrycho
For the "right tool for the problem", you're right; really, see up-thread
where someone posted the one-liner.

For MSVC over MinGW/Clang: part of my point here was to first learn and then
document for the community how you do cross-compilation for MSVC. There are
lots of projects out there where being able to link against MSVC is important,
and it's also _harder_ than linking against MinGW (which would have just been
`rustup target add x86_64-pc-windows-gnu` and `cargo build --release
--target=x86_64-pc-windows-gnu`, I believe; no extra linker stuff needed), so
there's more value in documenting it and putting it out there for MSVC.

~~~
MayeulC
Thanks, I didn't realise that it was meant to be this way. To me, it sounded a
bit like MSVC was the only option, and you had to install if for cross
compiling.

Since this is actually harder to do (from your own post), I worry a bit that a
beginner might try to do it right away, to the risk of failing at it.

------
denfromufa
This guy has likely not prototyped in environment such as Jupyter notebooks or
ptipython. It is not just language - there is whole ecosystem build around
Python scripting: pandas, matplotlib, numpy, etc. And don't forget about
debuggers and IDEs once your projects grow out of scripting environment. Did I
mention hooking up to GUI or web app?

~~~
chriskrycho
I've done a lot in those kinds of things, actually; they're _awesome_. I don't
feel obliged to mention every possible alternative in every blog post; that
would be absurdly tiring to do, and probably wouldn't add much value. (Edited
so it didn't read as hostile as the original version of the comment did.)

------
GrumpyNl
Its all about using the right tools / language for the job. And most of the
solutions mentioned here are not the right tool for the job. Install python??
install this, install that. All the guy needs is a simple .exe file for
windows that doesn't come with a manual howto install it.

------
tigershark
Was it too difficult to ask his friend to do right click -> create text
document-> open it and write 'ren STAR.cha STAR.txt' -> save it as rename.bat
and double click on it? Seriously, I'm not sure if this whole thing is a
joke...

edit: not sure why I cannot write the jolly character here

~~~
chriskrycho
It was an excuse to figure out the cross-compilation story with a tiny tool;
he got his tool, I got my experience with a part of the Rust ecosystem I
hadn't interacted with before. It was a win all around. (Note as well that I
said explicitly that I asked if this was a "just give me a tool" or a "teach
me something about scripting" kind of day!) :)

------
pwdisswordfish
Doesn't Windows have a built-in JavaScript runtime, the Windows Script Host?
Sure, it may not be a very pretty language either, but it's still relatively
sane compared to batch scripts. (I can't speak of PowerShell.)

~~~
nurettin
I do like activex/js and wsh, but Wsh might require permissions to modify the
filesystem, so installation/setup step can be harder than just copying and
running a statically compiled executable.

~~~
pwdisswordfish
Last time I checked, doing new ActiveXObject("Scripting.FileSystemObject") did
not require any extra 'permissions'.

~~~
nurettin
I remembered the problem, it was the execution of unsigned/remotely signed
_powershell_ scripts where you have to open powershell and give a
permission[1] by typing something like:

    
    
      Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
    

[1] [https://technet.microsoft.com/en-
us/library/bb613481.aspx](https://technet.microsoft.com/en-
us/library/bb613481.aspx)

------
ram_rar
I personally like rust as a systems language. But the syntax really hurts my
eyes as apposed to Python. A well crafted python code is soo easy to read.
Rust can soo become very messy.

------
nurettin
You could have done the same and given him a nice GUI in the process using
lazarus.

To install a cross-compiler on mac:

    
    
      $ fink install fpc-cross-i386-win32

------
rshm
I considered rust for daily scripts for the performance and statically
compiled binary. But had to give up when the complexities from borrower
checker came up and not to mention the limitation of libraries.

------
mobiuscog
[http://www.pyinstaller.org/](http://www.pyinstaller.org/)

Single file executable. Job done.

Of course, if you want to write something in Rust, it's not much use.

~~~
chriskrycho
Oh, nice! PyInstaller didn't have Python 3 support the last time I looked at
using it (mid-2015; I think it was in-work at that point), so I'm glad it's
landed.

------
mambodog
> Add the dependencies...

Nope. The beauty of a decent systems scripting language is that it includes
everything you need (and ideally is already installed everywhere).

~~~
kibwen
The author explains that the intended target is Windows, which has neither
Perl nor Python (nor even Bash) installed by default, so "already installed
everywhere" is already off the table. At that point, since Rust can produce
static binaries, it doesn't matter what deps you pull in.

------
evmar
By the way, to solve the specific problem mentioned in the article, see "man 1
rename".

~~~
saghm
Is this available on Windows? The author made it pretty clear the target user
was on a Windows machine

~~~
k1t
The Windows rename command doesn't support recursively processing subfolders,
but it can be achieved using one line of powershell:

    
    
      Get-ChildItem . -Recurse -Include *.cha | Rename-Item -NewName { $_.name -Replace '\.cha','.txt' }

~~~
flukus
From what I remember Include will only match items from the base directory and
powershell gets stupidly complicated very quickly:

[http://flukus.github.io/2015/03/13/2015_03_13_Powershell-
is-...](http://flukus.github.io/2015/03/13/2015_03_13_Powershell-is-a-Joke/)

~~~
oblio
That compares Powershell to Nant. Nant tasks (inspired by Ant tasks) are more
powerful than regular commands. Not even shell commands match those. He's
comparing apples with an apple pie there.

~~~
flukus
I started the article as a nant vs psake (PowerShell based build tool). Psake
relies on PowerShell tools for things like copying files, which makes sense.

I'm working on a similar one using make instead, which uses shell commands and
it's a lot better than both.

------
jasoncchild
This...felt misleading.

------
orcasauce
Does Rust really support macOS, or did he mean to say OSX?

~~~
Etzos
OS X was renamed to macOS, so they are the same thing as far as I know.

~~~
collyw
I remember macOS as the one before OS X. They changed it back again?

~~~
cpeterso
System → Mac OS → Mac OS X → OS X → macOS

------
uros678
One could probably get this done with one line of powershell code.

~~~
notriddle
I would have, but I have a Windows box. Our OP has a Mac, so testing the
script would be hard.

------
Annatar
The amount of contortions the author has had to go through is ridiculous, and
all because the target operating system is Windows, and doesn't yet ship a
production ripe UNIX userland (hence no AWK, sed, or zsh/tcsh/ksh out of the
box). As a colleague of mine always says: _give Wintendo no chance!_

~~~
mathw
Despite that, Windows is still the most popular desktop OS in the world by an
enormous margin. You don't help a friend who needs to rename a load of files
by saying "well, it'd be much easier if you first installed Linux". Or cygwin,
or even the Windows Subsystem for Linux if they're running Windows 10
Anniversary Update.

~~~
Annatar
You help a friend by giving him a one liner COMMAND.COM shell script, instead
of turning it into a cross-compiling hackfest just because you're a Rust
fanboy (in author's own words).

~~~
ZoFreX
How is the one-liner shell script more helpful to the friend than the
resulting binary? Yes it was convoluted but the point was the code author had
to jump through hoops, not the end user.

~~~
Annatar
Then the code author should have jumped through the hoops to learn Windows
shell scripting, instead of purposely overcomplicating.

When I see things like these, it honestly makes me hate computers and IT.

~~~
chriskrycho
No real hoops to jump; I'm sure I could have googled the batch script
invocation for him easily.

Again: the point was simply to use an interesting "hook" and then segue into
providing resources on cross-compiling with a super-simple example.

------
blub
There's lots of room for improvement here and I'm not sure Rust is the right
tool for the job.

First of all, why doesn't this have a UI? It would be much easier for the
friend to select the folder with the .cha files and they could see a nice
progress bar while they are renamed.

However, if there are few files the renaming process would be too fast and the
progress bar would flicker. An easy solution is to add sleep calls in the
worker thread to ensure that the progress is visible.

Of course the user could have lots of .cha files, and the friend might get
bored. A popular pattern is to display an overview of the program features in
picture + text format while a long procedure is running. There could be one
about .cha file renaming for instance.

It might make sense to also show ads, depending on the monetization strategy.
Maybe the friend wants to buy something and they don't realise it yet.

Finally, when the whole thing is done, the friend should be offered the option
to post it on twitter and/or facebook. Something along the lines "I have just
renamed 100 .cha files using rename-it. Try it yourself at <address>". The
address needs to be different from the blog, probably an SPA, but I'm not an
expert at that. And one more tip: don't ask for the facebook login before the
renaming, this makes users suspicious. It's much better to ask before posting
and explain why you need it. This builds trust.

I said that Rust is not the right tool. I would maybe try Electron, it's also
cross-platform, but the code can be reused on the back-end. For instance one
can upload a zip of all their .cha files and they get a zip of txt files back.

Ultimately desktop apps such as these are a thing of the past. But I guess
it's a nice exercise.

