Normally in node files I just put
#!/usr/bin/env node
at the top and make it executable to create a file that can be run from a bash terminal. However if I do that in a Typescript file, the compiler says "error TS1001: Unexpected character "#"" and refuses to compile it. So how can I make a shell executable node file with Typescript?
See https://github.com/Microsoft/TypeScript/blob/master/bin/tsc for an example. Basically have a dummy file without the .js extension and just require the actual .js file.
E.g. In file named tsc:
#!/usr/bin/env node
require('./tsc.js')
You were right to report the bug to Microsoft, and they were wrong to close it as wontfix.
Until it is fixed, here's a workaround. Paste the following into a text file and save it as shebangify:
#!/usr/bin/env node
var fs = require('fs');
var path = process.argv[2];
var data = "#!/usr/bin/env node\n\n";
data += fs.readFileSync(path);
fs.writeFileSync(path, data);
(N.B. To keep this answer concise, the code above doesn't have any error-checking or other refinements, so use at your own risk or use this instead. Also, see this SO question for more info about prepending to files.)
Make the file executable with by using a terminal to navigate to the file's directory and executing:
$ chmod +x shebangify
Once you have created a Typescript program (e.g. called myscript.ts) that you wish to compile and turn into a shell script (e.g. called myscript), do so by executing a sequence along these lines in your terminal:
$ tsc --out myscript myscript.ts ; ./shebangify myscript ; chmod +x myscript
If you have TypeScript and ts-node installed globally:
npm install typescript ts-node -g
You can now easily do this with:
#!/usr/bin/env ts-node
console.log('Hello world')
I don't have enough reputation points to post a comment, but I'd just thought it'd be good for everyone to know that I opened a new issue on GitHub since that's what the Typescript devs are using to track things like this: https://github.com/Microsoft/TypeScript/issues/2749 .
In case anyone is still struggling with making it work, the ts file should start with #! node instead of #!/usr/bin/env node, and tsc will take care of the rest.
I've never been able to get ts-node to work, so I finally made my own way to write shell scripts in TypeScript. If there were a package manager for Bash I would make a package, but there isn't, so I just put this script in my path as ts-exec:
#!/usr/bin/env bash
file_to_run="$1"
basename=`basename "$1"`
tmp_prefix=`basename "$BASH_SOURCE"`
TMPDIR=`mktemp -d -t "$tmp_prefix-XXXXXXXXXX"`
pushd "$TMPDIR" > /dev/null
cp "$1" "$basename.ts"
tsc "$basename"
node "$basename.js"
popd > /dev/null
rm -rf "$TMPDIR"
And now I can do things like this:
#!/usr/bin/env ts-exec
let greeting: string = "Hello World!";
console.log( greeting );
And it works.
Of course, it does have some limitations
It's only suitable for scripts that are confined to a single file
It doesn't do any error checking
It has implicit dependencies
It doesn't have an installer
... so basically it's for bash nerds who want to use TypeScript for small scripts that would be a pain to write as Bash scripts. I'm still baffled that ts-node doesn't cover this case, and I'd rather not have to futz with temp files that might get left behind and waste space if there's an error, but so far this covers my use-case. (Besides, I've got that cronjob that deletes everything in ~/tmp that's more than 31622400 seconds old every night, so stray temp files can't eat my whole system.)
As of ts-node v8.9.0 it seems like the recommended way to do this is with the following:
#!/usr/bin/env ts-node-script
If you don't want to install TS and ts-node globally and want to make the script runnable by the file path directly, create a file for example cli.ts next to local node_modules and put this as the first line
#!/usr/bin/env ./node_modules/.bin/ts-node
console.log('Wow');
Then execute by calling ./cli.ts
Related
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.
I always have this doubt and I don't know why the file inside the bin folder which create a simple http server doesn't have a .js extension.
Is there a reason behind this?
It's tradition on unix that executables don't have extension.
For example, on Linux and MacOS to list a directory you type:
ls
you don't type
ls.exe
Another example, to launch the Dropbox service on Linux you can type
dropbox
you don't type
dropbox.py
even though dropbox is just a text file containing Python code.
Unix (and also bash terminal on Windows) have a feature where if a file is marked as executable (using the chmod command) and the first line contains:
#!
.. then the shell (the program controlling the command line) will remove the first two characters (#!) and execute the rest of that first line. This is often called the shbang line (sh = shell, ! = bang).
Therefore, if you want to develop a command-line program in node.js all you need to do is start the file with #! /usr/bin/env node:
#! /usr/bin/env node
// ^
// |
// the 'env' command will find the correct install path of node
console.log('hello world');
Then use chmod to make the file executable:
chmod +x my-script.js
Of course, creating a program that ends in .js does not look "professional". For example you don't type gulp.js when you run gulp and you don't type npm.js when you run npm. So people follow tradition and make their executable scripts have no extension - it makes it harder for people to realise that you didn't write the program in C or assembly language.
Because www file is executable.
Open a console, go to the bin folder, and type ./www . The server will run.
Normally in node files I just put
#!/usr/bin/env node
at the top and make it executable to create a file that can be run from a bash terminal. However if I do that in a Typescript file, the compiler says "error TS1001: Unexpected character "#"" and refuses to compile it. So how can I make a shell executable node file with Typescript?
See https://github.com/Microsoft/TypeScript/blob/master/bin/tsc for an example. Basically have a dummy file without the .js extension and just require the actual .js file.
E.g. In file named tsc:
#!/usr/bin/env node
require('./tsc.js')
You were right to report the bug to Microsoft, and they were wrong to close it as wontfix.
Until it is fixed, here's a workaround. Paste the following into a text file and save it as shebangify:
#!/usr/bin/env node
var fs = require('fs');
var path = process.argv[2];
var data = "#!/usr/bin/env node\n\n";
data += fs.readFileSync(path);
fs.writeFileSync(path, data);
(N.B. To keep this answer concise, the code above doesn't have any error-checking or other refinements, so use at your own risk or use this instead. Also, see this SO question for more info about prepending to files.)
Make the file executable with by using a terminal to navigate to the file's directory and executing:
$ chmod +x shebangify
Once you have created a Typescript program (e.g. called myscript.ts) that you wish to compile and turn into a shell script (e.g. called myscript), do so by executing a sequence along these lines in your terminal:
$ tsc --out myscript myscript.ts ; ./shebangify myscript ; chmod +x myscript
If you have TypeScript and ts-node installed globally:
npm install typescript ts-node -g
You can now easily do this with:
#!/usr/bin/env ts-node
console.log('Hello world')
I don't have enough reputation points to post a comment, but I'd just thought it'd be good for everyone to know that I opened a new issue on GitHub since that's what the Typescript devs are using to track things like this: https://github.com/Microsoft/TypeScript/issues/2749 .
In case anyone is still struggling with making it work, the ts file should start with #! node instead of #!/usr/bin/env node, and tsc will take care of the rest.
I've never been able to get ts-node to work, so I finally made my own way to write shell scripts in TypeScript. If there were a package manager for Bash I would make a package, but there isn't, so I just put this script in my path as ts-exec:
#!/usr/bin/env bash
file_to_run="$1"
basename=`basename "$1"`
tmp_prefix=`basename "$BASH_SOURCE"`
TMPDIR=`mktemp -d -t "$tmp_prefix-XXXXXXXXXX"`
pushd "$TMPDIR" > /dev/null
cp "$1" "$basename.ts"
tsc "$basename"
node "$basename.js"
popd > /dev/null
rm -rf "$TMPDIR"
And now I can do things like this:
#!/usr/bin/env ts-exec
let greeting: string = "Hello World!";
console.log( greeting );
And it works.
Of course, it does have some limitations
It's only suitable for scripts that are confined to a single file
It doesn't do any error checking
It has implicit dependencies
It doesn't have an installer
... so basically it's for bash nerds who want to use TypeScript for small scripts that would be a pain to write as Bash scripts. I'm still baffled that ts-node doesn't cover this case, and I'd rather not have to futz with temp files that might get left behind and waste space if there's an error, but so far this covers my use-case. (Besides, I've got that cronjob that deletes everything in ~/tmp that's more than 31622400 seconds old every night, so stray temp files can't eat my whole system.)
As of ts-node v8.9.0 it seems like the recommended way to do this is with the following:
#!/usr/bin/env ts-node-script
If you don't want to install TS and ts-node globally and want to make the script runnable by the file path directly, create a file for example cli.ts next to local node_modules and put this as the first line
#!/usr/bin/env ./node_modules/.bin/ts-node
console.log('Wow');
Then execute by calling ./cli.ts
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
I want to use api-easy to test my REST app. I have it in the dependences inside the package.json, so when I run npm install it's installed in ./node_modules
I'm trying to add the api-easy to the path like
this question.
Since I'm using a Makefile I have this:
test:
#PATH="./node_modules/api-easy/node_modules/.bin:$PATH"
#echo $PATH
vows
#node ./test/tests.js
Note: api-easy depends on vows
The PATH var in not being updated, when I do the echo it returns me "ATH"(not the value), and then the command vows in not found.
How can I set properly the PATH in a Makefile?
In a make recipe, each command is executed as a separate process, so setting an environment variable in one command will not affect the others. To do what you want, you need to make sure all the related commands run in a single instance of the shell, where environment variables are passed as you would expect:
test:
#PATH="./node_modules/api-easy/node_modules/.bin:$$PATH"; \
echo $$PATH; \
vows; \
node ./test/tests.js
The trailing backslash tells make to concatenate a line with the one that follows it. Note also that you need to quote $ characters if you want them interpreted by the shell. Hence the $$.
I think something like this should do it:
export PATH="./node_modules/api-easy/node_modules/.bin:$PATH"
test:
vows
#node ./test/tests.js