Skip to content

Roger/y

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yel

the last command you will use

what is it?

y is a command that if everything goes as planed should end up being a shell, nonetheless it plays nice with other unix commands

no really, what is it?

what would happen if the shell spoke edn instead of text.

that and commands inspired by python/clojure

where is stderr?

there is no stderr

what?

thanks to tagged values in edn errors can flow from command to command going through stdout without affecting the actual data processing, by default if a command receives an error it will pass it along.

let's make an error:

$ y error :status 404 :reason '"not found"'

#y.E {"status" 404 "reason" "not found"}

now let's pipe it to cat:

$ y error :status 404 :reason '"not found"' | y cat

#y.E {"status" 404 "reason" "not found"}

no problem it went by without problem, now let's pipe that to something that does something useful:

$ y error :status 404 :reason '"not found"' | y range

[0 1 2 3 4 5 6 7 8 9]

so, one output but two inputs right?

you read my mind, you mean to the inputs and the command line options right?

well it happens that that's just a convenience, options are tagged values that can be sent at any point in the input.

yes, you are right (I read minds), you can change the options of a command on the fly:

$ y starts-with
asd
false

#y.O{:value "a"}
asd
true

dsa
false

#y.O{:value "x"}
xsdfs
true

$ y starts-with x
asd
false

xxx
true

$ y options x
#y.O {"value" "x"}

$ y options x | y starts-with
xsdffd
true

and the errno status codes?

I'm using HTTP status response codes, I may invent 8xx errors or something like that if I need new ones, but there are some useful ones there and people remember HTTP status codes more than errno ones ;)

but wait, that would suck for humans reading it!

nope, I will provide pretty printers and may detect if it's the last command and pretty print it for you.

let commands and computers speak formats they like and humans read formats they like, don't push text to computers or data formats to humans.

you are the Lennart Poettering of the shell

is that a compliment? :)

but, but, what would slashdot users say?

I can imagine it, if it's not broken don't fix it, the shell is ok as it is, that's not unix.

I can imagine the same people telling the same things to K&R when they were developing unix and C (replacing unix and C for what was mainstream at the moment)

show me more

a y command is a python module that will be loaded by name, the format is:

y <command> <args>

where command is a name and args can be any valid edn value, an example using our friend echo:

$ y echo :num 1 :bool 2 :symbol asd :keyword :lala

{"symbol" "asd" "num" 1 "bool" 2 "keyword" "lala"}

for now if the command arguments are not a vector, a list, a set or a single value it will be interpreted as a map (may change in the future)

$ y echo [1 2 3]

[1 2 3]

$ y echo "asd"

"asd"

$ y echo asd

"asd"

$ y echo :asd

"asd"

and what can I do with that?

I don't know here are some random commands:

$ y echo '"hi this is some text"' | y title
"Hi This Is Some Text"

$ y echo '"hi this is some text"' | y title | y shuffle
[" " "h" "o" "s" " " "T" " " "i" "e" "H" " " "i" "I" "m" "S" "e" "s" "x" "T" "t"]

$ y echo '"hi this is some text"' | y title | y shuffle | y join
"i THSx e Imtih Tssoe"

$ y echo '"hi this is some text"' | y title | y shuffle | y join | y lower
"xtesi is  htehmsoit "

$ y echo '"hi this is some text"' | y slice :start 1 :stop 7
"i this"

$ y echo '"hi this is some text"' | y slice :start 7 :stop 0 :step -1
" siht i"

$ seq 1 10 | y one-list
[1 2 3 4 5 6 7 8 9 10]

$ seq 1 10 | y one-list | y shuffle
[2 5 7 8 3 6 1 9 10 4]

$ seq 1 10 | y one-list | y shuffle | y sort
[1 2 3 4 5 6 7 8 9 10]

$ seq 1 10 | y one-list | y min
1

$ seq 1 10 | y one-list | y max
10

$ y range
[0 1 2 3 4 5 6 7 8 9]

$ y range :start 2
[2 3 4 5 6 7 8 9]

$ y range :start 2 :stop 7
[2 3 4 5 6]

$ y range :start 2 :stop 7 :step 2
[2 4 6]

$ y range :start 2 :stop 7 :step 2 | y reverse
[6 4 2]

all commands read from stdin so you can play with it from there:

$ y cat
hi
hi
hello
hello
^D

first, last, nth:

$ seq 1 10 | y first

1

$ seq 1 10 | y first 3

1
2
3

$ seq 1 10 | y first 5

1
2
3
4
5

$ seq 1 10 | y first 20

1
2
3
4
5
6
7
8
9
10

$ seq 1 10 | y last

10

$ seq 1 10 | y last 3

8
9
10

$ seq 1 10 | y nth 5

5

$ seq 1 10 | y nth 2

2

$ seq 1 10 | y nth

1

$ seq 1 10 | y nth 20

nil

keep-keys, drop-keys:

$ y date-time

{"hours" 8 "second" 11 "year" 2013 "day" 15 "minute" 52 "month" 8}

$ y date-time | y drop-keys [year month day]

{"hours" 8 "second" 31 "minute" 51}

$ y date-time | y keep-keys [year month day]

{"month" 8 "year" 2013 "day" 15}

drop-first, drop-last:

$ seq 1 10 | y drop-first

2
3
4
5
6
7
8
9
10

$ seq 1 10 | y drop-first 3

4
5
6
7
8
9
10

$ seq 1 10 | y drop-last

1
2
3
4
5
6
7
8
9

$ seq 1 10 | y drop-last 3

1
2
3
4
5
6
7

$ seq 1 10 | y drop-last 30

$

not:

$ echo true | y not
false

$ echo false | y not
true

$ echo 1 | y not
false

$ echo 0 | y not
true

$ echo [] | y not
true

$ echo [1] | y not
false

$ y not
true
false

false
true

1
false

0
true
^D

bool:

$ echo [1] | y bool
true

$ echo [] | y bool
false

$ echo 1 | y bool
true

$ echo 0 | y bool
false

$ echo true | y bool
true

$ echo false | y bool
false

$ echo nil | y bool
false

any, all:

$ seq 1 10 | y all
true

$ seq 0 10 | y all
false

$ seq 1 10 | y any
true

$ seq 0 1 | y any
true

count:

$ seq 1 10 | y count
10

$ seq 1 20 | y count
20

$ echo 1 | y count
1

join:

$ seq 1 10 | y join :sep a
"1a2a3a4a5a6a7a8a9a10"

$ seq 1 10 | y join :sep -
"1-2-3-4-5-6-7-8-9-10"

$ seq 1 10 | y join
"12345678910"

replace:

$ echo -e "foo\nbar\nbaz" | y replace :old a :new x

"foo"
"bxr"
"bxz"

reverse:

$ seq 1 10 | y reverse

10
9
8
7
6
5
4
3
2
1

set:

$ echo -e "1\n2\n1" | y set

1
2

shuffle and sort:

$ seq 1 10 | y shuffle

8
5
4
7
6
3
10
9
1
2

$ seq 1 10 | y shuffle | y sort

1
2
3
4
5
6
7
8
9
10

slice (the generated seq is different on each example to keep the output short):

$ seq 1 8 | y slice :start 3

4
5
6
7
8

$ seq 1 5 | y slice

1
2
3
4
5

$ seq 1 20 | y slice :start 3 :stop 10 :step 2

4
6
8
10

$ seq 1 20 | y slice :start 3 :stop 5

4
5

many commands:

$ y ls | y keep-keys [type path size] | y group-by type | y get f | y flatten-1 | y sort-by size | y keep-keys [ path ]

will display a list of all the file paths under the current directory
sorted by size

it could be simpler but the idea is to show how commands compose

filtering:

$ y ls | y keep :is eq? :key type :value f | y p

-------+--------+---------+--------------------------+-----------------------------------------+--------------------------+------+-------
Uid    | Gid    | Mode    | Mtime                    | Path                                    | Atime                    | Type | Size
-------+--------+---------+--------------------------+-----------------------------------------+--------------------------+------+-------
ubuntu | ubuntu | 0100664 | Thu Aug 15 17:44:46 2013 | /home/ubuntu/src/yel/README.rest        | Thu Aug 15 17:44:46 2013 | File | 8 KBs
ubuntu | ubuntu | 0100664 | Thu Aug 15 18:00:59 2013 | /home/ubuntu/src/yel/yel_utils.pyc      | Thu Aug 15 18:01:46 2013 | File | 15 KBs
ubuntu | ubuntu | 0100764 | Thu Aug 15 19:08:05 2013 | /home/ubuntu/src/yel/y                  | Thu Aug 15 19:08:05 2013 | File | 2 KBs
ubuntu | ubuntu | 0100664 | Thu Aug 15 19:09:34 2013 | /home/ubuntu/src/yel/yel_predicates.py  | Thu Aug 15 19:09:34 2013 | File | 1 KBs
ubuntu | ubuntu | 0100664 | Thu Aug 15 17:46:40 2013 | /home/ubuntu/src/yel/yel_utils.py       | Thu Aug 15 17:46:40 2013 | File | 9 KBs
ubuntu | ubuntu | 0100664 | Wed Aug 14 20:14:45 2013 | /home/ubuntu/src/yel/yel_status.pyc     | Wed Aug 14 20:16:28 2013 | File | 0 KBs
ubuntu | ubuntu | 0100664 | Wed Aug 14 16:13:12 2013 | /home/ubuntu/src/yel/parser.out         | Wed Aug 14 14:30:53 2013 | File | 52 KBs
ubuntu | ubuntu | 0100664 | Thu Aug 15 19:09:36 2013 | /home/ubuntu/src/yel/yel_predicates.pyc | Thu Aug 15 19:09:51 2013 | File | 3 KBs
ubuntu | ubuntu | 0100664 | Wed Aug 14 15:21:48 2013 | /home/ubuntu/src/yel/yel_status.py      | Thu Aug 15 15:23:14 2013 | File | 0 KBs
ubuntu | ubuntu | 0100664 | Thu Aug 15 11:26:30 2013 | /home/ubuntu/src/yel/test.py            | Thu Aug 15 11:26:30 2013 | File | 0 KBs
ubuntu | ubuntu | 0100664 | Wed Aug 14 16:13:12 2013 | /home/ubuntu/src/yel/parsetab.py        | Wed Aug 14 16:14:40 2013 | File | 7 KBs
ubuntu | ubuntu | 0100664 | Wed Aug 14 20:04:00 2013 | /home/ubuntu/src/yel/.gitignore         | Wed Aug 14 20:04:10 2013 | File | 0 KBs
ubuntu | ubuntu | 0100664 | Wed Aug 14 20:14:45 2013 | /home/ubuntu/src/yel/parsetab.pyc       | Wed Aug 14 20:16:28 2013 | File | 7 KBs

$ y ps | y keep-keys [pid username cpu_percent status exe name memory_percent] | y keep pid [lt 200] | y p

$ y ls | y drop type f | y p

-------+--------+--------+--------------------------+---------------------------------+--------------------------+------+------Uid | Gid | Mode | Mtime | Path | Atime | Type | Size -------+--------+--------+--------------------------+---------------------------------+--------------------------+------+------ubuntu | ubuntu | 040775 | Thu Aug 15 18:01:46 2013 | /home/ubuntu/src/yel/edn_format | Thu Aug 15 18:02:38 2013 | Dir | 4 KBs ubuntu | ubuntu | 040755 | Wed Aug 14 15:56:56 2013 | /home/ubuntu/src/yel/pyrfc3339 | Thu Aug 15 15:57:34 2013 | Dir | 4 KBs ubuntu | ubuntu | 040775 | Thu Aug 15 19:12:21 2013 | /home/ubuntu/src/yel/.git | Wed Aug 14 20:04:03 2013 | Dir | 4 KBs ubuntu | ubuntu | 040775 | Thu Aug 15 19:16:33 2013 | /home/ubuntu/src/yel/commands | Thu Aug 15 19:12:19 2013 | Dir | 4 KBs

$ seq 0 1 10 | y any asd? #y.E {"status" 404 "reason" "Invalid predicate 'asd?'"}

$ seq 1 10 | y any zero? false

$ seq 0 10 | y any zero? true

$ seq 0 10 | y all int? true

$ seq 0 10 | y all even? false

$ seq 0 10 | y all false

$ seq 0 10 | y any true

all collection functions apply to units (an edn value on a line for now)?

yes, but you can use map to apply a command to each item in a unit if it's a sequence:

$ y ls | y keys

["uid" "gid" "mode" "mtime" "path" "atime" "type" "size"]
["uid" "gid" "mode" "mtime" "path" "atime" "type" "size"]
["uid" "gid" "mode" "mtime" "path" "atime" "type" "size"]

$ y ls | y keys | y map upper

["UID" "GID" "MODE" "MTIME" "PATH" "ATIME" "TYPE" "SIZE" ]
["UID" "GID" "MODE" "MTIME" "PATH" "ATIME" "TYPE" "SIZE" ]
["UID" "GID" "MODE" "MTIME" "PATH" "ATIME" "TYPE" "SIZE" ]

things to define

how to differentiate commands that work on collections on each line and the ones that works on the whole input as a collection?

  • prefix/suffix?
  • option?
  • docs?

commands

  • reduce

unix commands

  • df
  • free
  • recursive ls
  • pwd

license

GPL v3 (may change my mind in the future)

About

the last command you will use

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%