kristopolous / TickTick

JSON in your Bash scripts
http://9ol.es/TheEmperorsNewClothes.html
Other
579 stars 55 forks source link

"Portable" (no debug magic) mode using HERE-documents (<<'EOF') #44

Open Artoria2e5 opened 4 years ago

Artoria2e5 commented 4 years ago

A lot of people are requesting ticktick for some other shell xsh where debug facilities may be nonexistent. A way to get that job done is to write a function that reads from its stdin, transpiles the code, and runs eval -- no caller magic needed! It's going to work in interactive shells too!

# The function should look like this...
tt() {
  eval "$(__tick_fun_tokenize_expression | __tick_fun_parse_expression)"
}
# don't ask me about disabling the rest of the magic i don't know okay?

People can then write blocks of JSON for that in here-documents and one-line here-strings. They are a bit more tedious, but that is expected. For example, instead of the example, we can say:

#!/bin/bash
TICKTICK_NOMAGIC=1
. ticktick.sh

bob=Bob
tt <<'EOF'
  people = {
    "HR" : [
      "Alice",
      $bob,
      "Carol"
    ],
    "Sales": {
      "Gale": { "profits" : 1000 },
      "Harry": { "profits" : 500 }
    }
  }
EOF

function printEmployees() {
  echo
  echo "  The $(tt <<< 'people.Engineering.length()') Employees listed are:"

  for employee in $(tt <<< 'people.Engineering.items()'); do
    printf "    - %s\n" ${!employee}
  done

  echo 
}

echo Base Assignment
tt <<< 'people.Engineering = [ "Darren", "Edith", "Frank" ]'
printEmployees

newPerson=Isaac
echo Pushed a new element by variable, $newPerson onto the array
tt <<< 'people.Engineering.push($newPerson)'
printEmployees

echo Shifted the first element off: $(tt <<< 'people.Engineering.shift()')
printEmployees

echo Popped the last value off: $(tt <<< 'people.Engineering.pop()')
printEmployees

echo Indexing an array, doing variable assignments

person0=$(tt <<< 'people.HR[0]')
echo $person0 $(tt <<< 'people.HR[1]')

(Note the quotes on EOF -- that prevents the shell from expanding $bob on its own prematurely. And the quotes on (), because when they poke out they make a syntax error. The quotes on [0] is there because it can mean a glob, and you don't want to risk having a file called people.HR0 and messing this up.)


kristopolous commented 4 years ago

hey that's pretty clever. good work.

kristopolous commented 4 years ago

isn't <<< a bashism?

kristopolous commented 4 years ago

for instance, dash, from busybox doesn't have it: Redirection operators: < > >| << >> <& >& <<- <>

kristopolous commented 4 years ago

nor does the old as dirt CSH || && | ^ & == != =~ !~ <= >= < > << >> + - * / % ! ~ ( )

kristopolous commented 4 years ago

don't get me wrong, I love the hack but it doesn't fix the dash/csh/ksh/tcsh problem

kristopolous commented 4 years ago

I also don't really understand why jq and the more serious programs like that aren't alternatives ... maybe you can tell me ... what's your actual usecase?

kristopolous commented 4 years ago

I mean the real real real way to do this would be to just jack the interpreter as a fat wacky wrapper ... essentially have a program say, /usr/bin/crash that does all the intepreter stuff and then do this

#!/usr/bin/crash
... proceed as usual ...
XLTechie commented 4 years ago

isn't <<< a bashism?

Yes.

http://mywiki.wooledge.org/HereDocument?action=show&redirect=HereString

Artoria2e5 commented 4 years ago

Yeah, that's a bashism. printf %s "somestuff" | tt can be used to go around it though. It might be available in some version of ksh, but I am not sure.

CSH is out of the question: the syntax isn't even in the same family of POSIX/Bourne shells. And then there's that one epic rant about how awful CSH is for programming called CSH programming considered harmful.

kristopolous commented 4 years ago

I was in the space between sleep and awake this morning when I had more visions of the crash system ... essentially we'll need to either permanently do portable syntax (like '[' instead of '[[') or have a converter. The '[[' is sooo much faster ...

A bash-4 -> POSIX SH transpiler sounds like something that probably already exists in the world - I took enough of computer theory to know it's possible to completely make this since POSIX SH is tightly bound ... It's been around for 31 years I bet this exists. Let me look

kristopolous commented 4 years ago

hrmm ... "checkbashism" and "shellcheck" are the internet recommendations ... that's lame. I want to have a magic converter as part of a build script.

kristopolous commented 4 years ago

I dunno ... I think I'll just ask stackexchange ... https://unix.stackexchange.com/questions/588862/is-there-a-bash-to-posix-transpiler let's see what happens.

edit: Apparently the silly doofuses at stackoverflow are uninformed dorks ... I don't have time to run a shell bootcamp for the supposed experts there. I'll do it myself.

kristopolous commented 4 years ago

about 8 years ago, I was asked for busybox dash support in #22 and that should probably be the reference interpreter here. There's sadly quite a bit of hacks that would need to be done. bash's string substitution in a variable for instance (${//}) doesn't seem to be there.

Unless I want this thing to crawl I think I'd have to rewrite chunks of it more heavily in awk and sed

XLTechie commented 4 years ago

Something I have wondered:

It claims to let you put JSON in bash scripts. When did it decide it had to support every bash varient on the planet?

Let it be bash.

You never claimed it supported dash, busybox, korn, or aunt Fanny's shhhh.

On Mon, 25 May 2020, chris mckenzie wrote:

about 8 years ago, I was asked for busybox dash support in #22 and that should probably be the reference interpreter here. There's sadly quite a bit of hacks that would need to be done. bash's string substitution in a variable for instance (${//}) doesn't seem to be there.

Unless I want this thing to crawl I think I'd have to rewrite chunks of it more heavily in awk and sed

Artoria2e5 commented 4 years ago

One of the things for magic-less even in bash is usability in an interactive shell. That's #20.

ewildgoose commented 3 years ago

bash's string substitution in a variable for instance (${//}) doesn't seem to be there.

I'm just checking my busybox shell right now and this works:

$ stringZ=abcABC123ABCabc; echo ${stringZ/abc/xyz}
xyzABC123ABCabc

Does this get us any further forward? The main thing we can't do with busybox is arrays.

I would love to get this working with my busybox systems so I can use it for simple config files. Nothing more than some fields with product type, version, etc. For various reasons it's helpful to have them in json.