Use xonsh to loop over files with ls - xonsh

I want to use xonsh to bzip several files in a directory. I first attempt this with the following:
$ ls
table_aa.csv table_amgn.csv table_csco.csv table_esrx.csv table_hal.csv table_jbl.csv table_pcg.csv table_zmh.csv
table_aapl.csv table_amzn.csv table_d.csv table_gas.csv table_hp.csv table_jpm.csv table_usb.csv
$ for fn in ls:
.. bzip2 fn
..
NameError: name 'ls' is not defined
OK, so I use $() explicitly
$ for fn in $(ls).split():
. bzip2 fn
bzip2: Can't open input file fn: No such file or directory.
bzip2: Can't open input file fn: No such file or directory.
Is there a better way to do this?
$ xonsh --version
('xonsh/0.3.4',)

You are very close with the second example. The only thing to note is that fn is a Python variable name, so you have to use #() to pass it to a subprocess:
$ for fn in $(ls).split():
. bzip2 #(fn)
Also, on v0.3.4, you could use regex globbing instead of ls,
$ for fn in `.*`:
. bzip2 #(fn)
And at least on master, you can now iterate through !() line-by-line, which means that the following will also work if you are wedded to ls:
$ for fn in !(ls):
. bzip2 #(fn)

Using ls:
for fn in !(ls):
print(fn.rstrip())
Using globs (available in regex, shell, and path varieties):
for fn in g`*`:
print(fn)
Using Python APIs (see the os, glob, or pathlib modules):
import os
for fn in os.listdir():
print(fn)

Related

How to Compile Agda Hello World on Nixos?

On nixos, I am trying to compile the hello world example listed in the agda documentation.
In my working directory, I have the following:
The hello-world agda program, hello-world.agda:
module hello-world where
open import IO
main = run (putStrLn "Hello, World!")
A nix shell file, shell.nix:
{ pkgs ? import <nixpkgs> { } }:
with pkgs;
mkShell {
buildInputs = [
(agda.withPackages (ps: [
ps.standard-library
]))
];
}
To enter a shell with the standard-library dependency available, I ran $ nix-shell shell.nix.
Then, trying to compile the program, I ran $ agda --compile hello-world.agda, as advised by the linked agda hello world documentation.
But that gave me the following error:
$ agda --compile hello-world.agda
Checking hello-world (/home/matthew/backup/projects/agda-math/hello-world.agda).
/home/matthew/backup/projects/agda-math/hello-world.agda:3,1-15
Failed to find source of module IO in any of the following
locations:
/home/matthew/backup/projects/agda-math/IO.agda
/home/matthew/backup/projects/agda-math/IO.lagda
/nix/store/7pg293b76ppv2rw2saf5lcbckn6kdy7z-Agda-2.6.2.2-data/share/ghc-9.0.2/x86_64-linux-ghc-9.0.2/Agda-2.6.2.2/lib/prim/IO.agda
/nix/store/7pg293b76ppv2rw2saf5lcbckn6kdy7z-Agda-2.6.2.2-data/share/ghc-9.0.2/x86_64-linux-ghc-9.0.2/Agda-2.6.2.2/lib/prim/IO.lagda
when scope checking the declaration
open import IO
It seems it should be finding the standard library, since I'm running from the nix-shell with agda's standard-library specified, but that error on open import IO looks like the standard library is somehow still not found.
Any idea what the problem is likely to be?
Or what else I can do to get agda working on nixos?
You might need to create a defaults file in AGDA_DIR (which typically refers to ~/.agda/ unless overwritten through environment variable) with the libraries you want to make available to your program:
echo standard-library >> ~/.agda/defaults
which should make the compiler automatically load the standard library.
Alternatively, you can pass them in on the command-line:
agda -l standard-library
or use a project-local .agda-lib file as follows:
name: my-libary
depend: standard-library
include: -- Optionally specify include paths
You should not need to specify the include paths with Nix, but in case you do, you can use the -i command line flag or add the path to the standard-library.agda-lib file in ~/.agda/libraries.

How to run m4 inline

I have the following to process a file:
$ vim file2
define(add2, `eval($1+$2)')
Adding 2+4=add2(2,4)
And to run:
$ m4 file
Adding 2+4=6
Is there a way to run m4 with the file contents inline? For example something like:
$ m4 <inline>
define(add2, `eval($1+$2)')
Adding 2+4=add2(2,4)
<ctrl-d>
# Adding 2+4=6
How could that be done?
One option is to the 'interactive mode':
-e, --interactive
unbuffer output, ignore interrupts
In which case you can do:
IM-MM:DD_Objects david$ m4 -e
define(add2, `eval($1+$2)')
Adding 2+4=add2(2,4)
Adding 2+4=6

xonsh "which" equivalent - how to test if a (subprocess mode) command is available?

I would like to test (from xonsh) if a command is available or not. If I try this from the xonsh command prompt:
which bash
Then it works:
user#server ~ $ which bash
/usr/bin/bash
But it does not work from xonsh script:
#!/usr/bin/env xonsh
$RAISE_SUBPROC_ERROR = True
try:
which bash
print("bash is available")
except:
print("bash is not available")
Because it results in this error:
NameError: name 'which' is not defined
I understand that which is a shell builtin. E.g. it is not an executable file. But it is available at the xnosh command prompt. Then why it is not available inside an xonsh script? The ultimate question is this: how can I test (from an xonsh script) if a (subprocess mode) command is available or not?
import shutil
print(shutil.which('bash'))
While nagylzs' answer led me to the right solution, I found it inadequate.
shutil.which defaults to os.environ['PATH']. On my machine, the default os.environ['PATH'] doesn't contain the active PATH recognized by xonsh.
~ $ os.environ['PATH']
'/usr/bin:/bin:/usr/sbin:/sbin'
I found I needed to pass $PATH to reliably resolve 'which' in the xonsh environment.
~ $ $PATH[:2]
['/opt/google-cloud-sdk/bin', '/Users/jaraco/.local/bin']
~ $ import shutil
~ $ shutil.which('brew', path=os.pathsep.join($PATH))
'/opt/homebrew/bin/brew'
The latest version of xonsh includes a built-in which command. Unfortunately, the version included will emit an error on stdout if the target isn't found, a behavior that is not great for non-interactive use.
As mentioned in another answer, which exists in the current version of xonsh (0.13.4 as of 15/12/2022) so your script would work. However, it outputs its own error message so it's necessary to redirect stderr to get rid of it.
Also, unless you redirect its stdout as well (using all>), it migh be a good idea to capture its output so the final version would look like this:
#!/usr/bin/env xonsh
$RAISE_SUBPROC_ERROR = True
try:
bash = $(which bash err> /dev/null)
print(f"bash is available: {bash}")
except:
print("bash is not available")

How can I nix-env install a derivation from a nix expression file?

I've got a default.nix file that builds a derivation (at least my understanding of it).
{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc864" } :
nixpkgs.pkgs.haskell.packages.${compiler}.callCabal2nix "bhoogle" (./.) {}
I can successfully nix-build this. Is there a way I can install this into my user profile with nix-env directly? For example something like nix-env -i -f default.nix.
Otherwise I need to define a package in my system profile with something like:
example = pkgs.callPackage /home/chris/example/default.nix {};
Quite literally my initial guess (thanks #Robert):
nix-env -i -f default.nix
Documented in nix --help:
--file / -f path
Specifies the Nix expression (designated below as the active Nix expression) used by the --install, --upgrade, and --query
--available operations to obtain
derivations. The default is ~/.nix-defexpr.
If the argument starts with http:// or https://, it is interpreted as the URL of a tarball that will be downloaded and
unpacked to a temporary location. The tarball
must include a single top-level directory containing at least a file named default.nix.

Aspell dictionaries missing when installed into nix-shell

When I install the Aspell package with the Aspell dictionary for English into my global env using Nix on Mac OSX:
$ nix-env -iA nixpkgs.aspell nixpkgs.aspellDicts.en
Then Aspell behaves as I would expect:
$ aspell dump dicts
en
en-variant_0
...
However if I install the packages into a nix-shell then the Dictionary does not appear to be correctly installed:
$ nix-shell -p aspell aspellDicts.en --pure
$ aspell dump dicts
# nothing printed
$ echo 'word lister to check' | aspell --list
Error: No word lists can be found for the language "en_US".
Each of the following variations produce the same problem behaviour:
Installing into a nix-shell that is not pure,
Putting the nix expression into a default.nix file and just running nix-shell.
Installing other Aspell dictionaries
Can anyone advise how to get this working?
The aspell binary is wrapped by NixPkgs, to provide the installation paths through ASPELL_CONF environment variable, if not already specified. (For details, cat -v result/bin/aspell)
You can either specify ASPELL_CONF manually, or use the NIX_PROFILES environment variable. For example:
$ nix-build -E 'with import <nixpkgs> {};
buildEnv { name = "aspell-env"; paths = [aspell aspellDicts.en]; }'
$ NIX_PROFILES=./result ./result/bin/aspell dump dicts
en
en-variant_0
[...]
en_US-wo_accents
However, if you want to build a self-contained aspell install with dictionaries, you can use aspellWithDicts:
nix-build -E 'with import <nixpkgs> {}; aspellWithDicts (d: [d.en])'
This will hardcode the ASPELL_CONF, so you don't need to think of those environment variables again.

Resources