kristopolous / TickTick

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

TickTick hangs when initialized in an interactive shell #20

Open kristi opened 12 years ago

kristi commented 12 years ago

Initializing ticktick in an interactive bash shell causes the shell to hang

# Start a new bash shell without any extra environment variables
env - bash
# Try to initialize ticktick
. ticktick.sh

The source command doesn't complete. It just hangs.

kristopolous commented 12 years ago

Wow ... That's wonderful. Props. I never thought of doing that. What did you want it to do? I'm not being condescending, I'm genuinely interested. Did you think that then you could do multiline tick tick style json in the shell, interactively? That would be pretty wonderful but probably a different project.

Really though, what were trying to do?

EDIT: Crap. This is totally possible. Dear lord ... what an incredible piece of work this shell is.

kristi commented 12 years ago

Was just trying out your library. It's not unreasonable to enter commands into the interactive shell. I like to test commands manually in an interactive shell, then when things work, save them into a script file.

kristopolous commented 12 years ago

Ok I see. Yes, there is really no way to do that right now (not without a lot of work on my side). When you do . ticktick.sh

It actually uses a debugging feature to find out the file that you are including it from.

Then it reads the contents of your script. It replaces the back ticks with valid bash. You can see this by setting __tick_var_debug=1 at the top of your script, before the include.

For instance, the example script

#!/bin/bash

. ticktick.sh

bob=Bob

``
  people = {
    "HR" : [
      "Alice",
      $bob,
      "Carol"
    ],
    "Sales": {
      "Gale": { "profits" : 1000 },
      "Harry": { "profits" : 500 }
    }
  }
``

function printEmployees() {
  echo
  echo "  The ``people.Engineering.length()`` Employees listed are:"

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

  echo 
}

echo Base Assignment
`` people.Engineering = [ "Darren D", "Edith E", "Frank F" ] ``
printEmployees

newPerson="Isaac I"
echo Pushed a new element by variable, $newPerson onto the array
`` people.Engineering.push($newPerson) ``
printEmployees

echo Shifted the first element off: `` people.Engineering.shift() ``
printEmployees

echo Popped the last value off: `` people.Engineering.pop() ``
printEmployees

echo Indexing an array, doing variable assignments

person0=``people.HR[0]``
echo $person0 ``people.HR[1]``

If you put that variable in there and then run it you'll get this:

#!/bin/bash
__tick_var_debug=1

. ticktick.sh

bob=Bob

__tick_data_people_HR_000000000000="Alice"
__tick_data_people_HR_000000000001=$bob
__tick_data_people_HR_000000000002="Carol"
__tick_data_people_Sales_Gale_profits=1000
__tick_data_people_Sales_Harry_profits=500

function printEmployees() {
  echo
  echo "  The `__tick_runtime_length ${!__tick_data_people_Engineering_*}` Employees listed are:"

  for employee in ${!__tick_data_people_Engineering_*}; do
    printf "    - %s\n" "${!employee}"
  done

  echo 
}

echo Base Assignment
__tick_data_people_Engineering_000000000000="Darren D"
__tick_data_people_Engineering_000000000001="Edith E"
__tick_data_people_Engineering_000000000002="Frank F"
printEmployees

newPerson="Isaac I"
echo Pushed a new element by variable, $newPerson onto the array
__tick_runtime_push "$newPerson" __tick_data_people_Engineering_ ${!__tick_data_people_Engineering_*}
printEmployees

echo Shifted the first element off: `__tick_runtime_first ${!__tick_data_people_Engineering_*}`; __tick_runtime_shift ${!__tick_data_people_Engineering_*}
printEmployees

echo Popped the last value off: "$( __tick_runtime_last ${!__tick_data_people_Engineering_*} )"; __tick_runtime_pop ${!__tick_data_people_Engineering_*}
printEmployees

echo Indexing an array, doing variable assignments

person0=${__tick_data_people_HR_000000000000}

Basically your script gets totally rewritten by ticktick based on what you have in the back ticks, then the new code gets executed and the script stops parsing there.

That means that bash never tries to execute the real script that you wrote with the backticks because including ticktick basically hijacks the shell, makes a copy of your script in memory, rewrites it into valid bash, executes the rewritten in-memory version of your program and then exits.

This is possible because unlike in a compiled language such as C, bash only reads one line at a time. So it will execute your script line by line until either their are no lines left, it's told to exit, or it sees something it doesn't recognize and then exits with an error.

Normally, the tick tick syntax would be in the third group and bash would not go on. But because we tell it to exit, inside the first line of the program, inside of the ". ticktick.sh", that means that it never really "sees" the original, invalid, tick-tick style bash code. It's a wonderful little trick. I got the inspiration from CoffeeScript.

So it's very dependent on files and scripts. To do this inline is quite possible but I assure you, an even more difficult feat.

If you want to, you can use an inotify tool that will detect when your script gets written to disk and then executes it immediately. That's probably the closest thing you could do to get there without me writing this theoretical interactive shell hijacker (which sounds mighty scary)

XLTechie commented 4 years ago

@kristopolous wrote:

because including ticktick basically hijacks the shell, makes a copy of your script in memory, rewrites it into valid bash, executes the rewritten in-memory version of your program and then exits.

Ahem in memory, you say?

I think it only does it in memory for the main script that sourced ticktick.sh. Anything that script subsequently sources, seems to get written to a file in /tmp, with a name like /tmp/ymrjibble.skibble (though usually without the rhyming). Whether or not TickTick has to make any changes to that file.

At least, that's my understanding from the increasing number of files hanging out under /tmp, and the periodic errors like Missing ] on line 52 of /tmp/blahbloh.blih.

That said, nice post, and brilliant project!