TextExpander, Shell Scripts, & Node - node.js

I'm trying to execute some JS code as a Node shell script, but it doesn't seem to work and I can't tell why. Here's a simple example:
#!/usr/bin/env node
console.log("foo");
The above script should result in TextExpander inserting the text "foo" when triggered, but it doesn't. The equivalent in bash works just as expected:
#!/usr/bin/env bash
echo "foo"
I thought that perhaps the call to console.log() was not producing something where TextExpander was looking (although all the documentation I can find says that should print to stdout). I've even tried a workaround like this with no luck:
#!/usr/bin/env sh
echo `/usr/bin/env node -e "console.log(\"foo\");"`
I get no visible errors or any indication that something went wrong. I just end up with TextExpander inserting an empty string instead of "foo". Any TextExpander experts out that that might see something I'm missing? Running the non-working examples in the shell work fine, and TextExpander is supposed to just capture whatever goes to stdout. I'm not even sure how I could go about debugging this.

Make sure the directory where your node executable is installed is listed in the PATH environment variable that TextExpander will use. This is probably not the same PATH value one you get in your terminal. To verify if that's the problem, try doing #!/full/path/to/node as your shebang line instead of running env. My guess is node is installed either in /usr/local/bin/node or somewhere under your home directory and neither of those are in the PATH that TextExpander has while running.

You probably should add -e to your header:
#!/usr/bin/env node -e
Or
You probably should add -e to your header:
#!/path/to/node -e

Related

#reboot crontab has no effect

I have this crontab #reboot "/home/pi/Desktop/TV Scraper 2.0/run.sh" set up and for whatever reason it doesn't seem to run the bash file on reboot.
Typing "/home/pi/Desktop/TV Scraper 2.0/run.sh" on the terminal actually runs the script, so I know it's correct.
This is what's inside run.sh just in case:
#!/bin/bash
cd "/home/pi/Desktop/TV Scraper 2.0"
node ./app.js
I've also tried using #reboot root sh "/home/pi/Desktop/TV Scraper 2.0/run.sh" as well, but it doesn't work either.
How can I move forward with this? My knowledge of Linux is very limited. All I need is to have some Node and Python3 scripts run on every reboot. On Windows that's such an easy task: I've tried CRON, rc.local and autostart, nothing works.
My guess is that node is not available via cronjob, since its containing directory is not in your PATH environment variable. When you execute the script manually, it's probably available via PATH.
An easy fix for this is to use the full path, which you can get by executing which node. The result should be something like /usr/bin/node. Then you can use that, instead of just node.
For debugging purpose you can also redirect stdout and stderr to a file, so the last line in your script would look like this:
/usr/bin/node ./app.js &>/tmp/cron-debug.log
If that doesn't fix it, i would rename the directory "TV Scraper 2.0" and replace the whitespace characters with something like an underscore. Directory and file names are less likely to cause problems if you avoid whitespaces.

Command works in terminal but not as alias in profile.d

I have a problem regarding an alias file in /etc/profile.d/. This isn't anything important. I'm just interested why it isn't working as expected.
So basically I have the file 00-alias.sh at the path mentioned above and I wanted to make a shortcut which reads a specific line of a file. So this is my code:
alias lnn='sed -n "${1}p" < "${2}"'
With that code I should be able to perform a command like
$ lnn 4 test.txt
However, this doesn't work. I simply get the error
-bash: : No such file or directory
Now I thought, ok, maybe relative paths aren't working because the file is located at the path /etc/profile.d/00-alias.sh
So I went ahead and made a new alias like
alias pwd2='echo $(pwd)'
Then updated the profile.d with
source /etc/profile.d/00-alias.sh
And just tried pwd2 but that echoed the path I was currently in. So in theory the file can be found with the command I wrote. I still tried to pass the file to my alias with absolute path like
$ lnn 4 /var/test.txt
Still same error as above.
But, if I enter the command of the alias in the terminal like
sed -n "4p" < test.txt
It works perfectly fine. No matter if I put quotes around test.txt
And here is another weird thing: If I write
alias lnn='sed -n "${1}p" < ${2}'
without the quotes around ${2} I get the error
-bash: ${2}: ambiguous redirect
In the terminal it works just fine...
So, what am I doing wrong? Does anyone have an idea on this? I'd love to know my mistake. But as I said, this isn't a real problem as I'm just curious why bash behaves like that.
Aliases in bash do not take parameters of any form. Save the pain and use a function instead.
function lnn() {
sed -n "${1}p" < "${2}"
}
Add the function to the file 00-alias.sh and source it once before calling the function from command-line.
source /etc/profile.d/00-alias.sh
lnn 4 test.txt
See more information at BashFAQ/80: How can I make an alias that takes an argument?
You can't. Aliases in bash are extremely rudimentary, and not really suitable to any serious purpose. The bash man page even says so explicitly:
An excerpt from the GNU bash man page, about aliases
.. There is no mechanism for using arguments in the replacement text. If arguments are needed, a shell function should be used.
On a side note the problem has nothing to do with relative paths (or) so, just remember aliases are not allowed in scripts. They're only allowed in interactive shells. If you're writing a script, always use a function instead.

How node script can run in my current bash context (process)?

In bash You can source or . to run some bash script in your current context. So if you have e.g. file foo with alias bar='echo bam' in it and when You run it like
$ . foo
it will source this alias from file foo into your current context.
I know if I normally run node script with first line like #!/usr/bin/env node then this script is run in sub-shell or as separate process. I want to avoid this and make node script act on my current bash process (context).
How can I run node script that alter my current bash context?
ps: Any example is good. Node script can only change my directory but again it must happen in my current bash context.
ps2: Sub question: If it's impossible in node (and it's very hard for me to believe in this) or it's very complicated then is it possible in other language? Like PHP, Java, Ruby (I don't ask for C because it's obvious :) and if so please give me some example.
I've struggled with this same problem when writing my Node implementation of wd. AFAIK there is no way to do what you want to do for reasons already known to you. However, if you want to use node in a sourced shell script, there is a way around it, kind of.
So you can't source a node script, but what you can do is execute node scripts in a sourced shell script. Performance isn't great, but it works. For example, you can't put process.chdir('/tmp'); in a node script and expect it to change the current working directory in your current process. But what you can do is make a node script that console.logs a directory and execute that in a sourced shell script with something like cd $(node myscript.js). For an example of this, check out the code in my project I linked above. There I use a bash function to source a shell script of a globally installed npm module which then executes JS to change the current dir (at least, in bash and zsh). It's not exactly pretty, but it works.
I know it's not the answer you were looking for, but it's as close as I've found a way to use node to manipulate the current bash context. I actually found this question because I was just trying to refactor and look for a better way to do this.. If I ever do find that better way I'll let you know ;-)

Running Visual Studio Code from the CLI in Linux

I've downloaded and "installed" VSCode for Linux. I have placed the app in /home/Christian/Apps/VSCode/ and symlinked the executable to /usr/bin/code.
When I use this method to start Code it hijacks the terminal (expected I guess) and also dumps a lot of STDERR stuff at the same time.
If I redirect STDERR to a file, for example like
code 2> ~/.logs/VSCode-`date +%Y%m%d%H%M%S.log` &
Then I can get it to give me back my prompt, and it's silent (logging everything to the filename I gave it).
I was thinking of making this an alias, but then I realized I can't inject arguments ($1 $2 $3) in an alias. And I usually want to start code with code filename.js or code ..
What is the correct way to launch an application like this "in the background"?
Instead of making a symlink to the executable, create a bash script like this:
#!/bin/bash
/path/to/VSCode/Code "$#" 2>/dev/null &

shell script not running via crontab, runs fine manually

I have tried exporting my paths and variables and crontab still will not run my script. I'm sure I am doing something wrong.
I have a shell script which runs a jar file. This is not working correctly.
After reading around I have read this is commonly due to incorrect paths due to cron running via its own shell instance and therefore does not have the same preferences setup as my profile does.
Here is what my script looks like today after several modifications:
#!/bin/bash --
. /root/.bash_profile
/usr/bin/java -jar Pharmagistics_auto.jar -o
...
those are the most important pieces of the script, the rest are straightforward shell based.
Can someone tell me what I am doing wrong?
Try specifying the full path to the jar file:
/usr/bin/java -jar /path/to/Pharmagistics_auto.jar -o
I would just tell you what you have already ruled out: Check your path and environment.
Since you have alredy done this, start debugging. Like write checkpoints into a logfile to see how far your script gets (if even started at all), check the cronjob log file for errors, check your mail (cron sends mails on errors) and so on ...
Not very specific, sorry.
"exporting my paths and variables" won't work since crontab runs in a different shell by a different user.
Also, not sure if this is a typo in how you entered the question, but I see:
usr/bin/java
...and I can't help but notice you're not specifying the fully qualified path. It's looking for a directory named "usr" in the current working directory. Oft times for crontab, the cwd is undefined, hence your reference goes nowhere.
Try specifying the full path from root, like so:
/usr/bin/java
Or, if you want to see an example of relative pathing in action, you could also try:
cd /
usr/bin/java
A few thoughts.
Remove the -- after the #!/bin/bash
Make sure to direct script output seen by cron to mail or somewhere else where you can view it (e.g. MAILTO=desiredUser)
Confirm that your script is running and not blocked by a different long-running script (e.g. on the second line, add touch /tmp/MY_SCRIPT_RAN && exit)
Debug the script using set -x and set -v once you know it's actually running
Do you define necessary paths and env vars in your personal .profile (or other script)? Have you tried sourcing that particular file (or is that what you're doing already with /root/.bash_profile?)
Another way of asking this is: are you certain that whatever necessary paths and env vars you expect are actually available?
If nothing else, have you tried echo'ing individual values or just using the "env" command in your script and then reviewing the stdout?
provide full paths to your jar file, and what user are you running the crontab in? If you set it up for a normal user, do you think that user has permission to source the root's profile?

Resources