Run code only if script called from the command line
It is common to put this at the bottom of your script:
if __FILE__==$0
# this will only run if the script was the main, not load'd or require'd
end
Because I like to see the main action at the top of my file, I usually put a def run!
as the first method in the file and then end the file with:
run! if __FILE__==$0
How can I run a function from a script in command line?
If the script only defines the functions and does nothing else, you can first execute the script within the context of the current shell using the source
or .
command and then simply call the function. See help source
for more information.
Run only parts of shell script with arguments
You can abstract the segments of your code into functions, then trigger which functions should be run with command line arguments. In the example below, you can run the script with, e.g. ./script.sh --install-requirements --aws-copy
, or equivalently ./script.sh -i -a
.
If you prefer, case
statements (similar to switch
in C/C++) can be used instead of the multiple if
s below, see resources at the bottom for more details.
If you would like to use command line arguments inside of the functions, you can forward them with $@
, like this: InstallRequirements "$@"
. You can also pass any other arguments, like this: InstallRequirements arg1 arg2
, the function will see them the same way a script sees command line arguments.
Also note it's almost always better to enclose variables in double quotes: rm -rf "$filename"
instead of rm -rf $filename
. The rm
without the quotes is very dangerous if the filename contains spaces.
#!/bin/bash
function InstallRequirements {
pip install -r ./docker/requirements.txt
}
function ZipFile {
ZIP_FILE=spark.zip
zip -r "$ZIP_FILE" file.py
}
function AwsCopy {
S3_BUCKET_PATH=$S3_BUCKET_PATH
aws s3 cp "$ZIP_FILE" "$S3_BUCKET_PATH/lib/"
}
###
for arg in "$@"; do
if [[ "$arg" = -i ]] || [[ "$arg" = --install-requirements ]]; then
ARG_INSTALL_REQUIREMENTS=true
fi
if [[ "$arg" = -z ]] || [[ "$arg" = --zip-file ]]; then
ARG_ZIP_FILE=true
fi
if [[ "$arg" = -a ]] || [[ "$arg" = --aws-copy ]]; then
ARG_AWS_COPY=true
fi
done
###
if [[ "$ARG_INSTALL_REQUIREMENTS" = true ]]; then
InstallRequirements
fi
if [[ "$ARG_ZIP_FILE" = true ]]; then
ZipFile
fi
if [[ "$ARG_AWS_COPY" = true ]]; then
AwsCopy
fi
Resources:
- Linuxize: Bash Functions
- Unix & Linux Stack Exchange: Pass arguments to function exactly as-is
- Bash Guide for Beginners: 7.3. Using case statements
- Nick Janetakis: Here's Why You Should Quote Your Variables in Bash
Rscript detect if R script is being called/sourced from another script
EDIT
Okay, this is a LOT more like python's __name__
trick. (Previous answer below, kept for historical reasons.)
function1 <- function(etc,etc) {}
function2 <- function(etc,etc) {}
if (sys.nframe() == 0L) {
library(optparse)
# ...
}
It is about as minimalist as one could hope for, does not require the source
ing script to know anything about it, and seems to work well even when nested.
Other possible mechanisms could be used (additional functions required) by looking at script names, per Rscript: Determine path of the executing script. Many plausible (some really good) solutions exist there, but they all require a pre-defined function not defined in a base package (or non-trivial code included in the script to be sourced). If you want to "assume package X is installed", then your script becomes potentially non-portable.
(Previous answer, I suggest you use above.)
I'll throw this out as a hack ... it's only slightly less janky than your workaround, but it relies on the calling script knowing something of what the called script is testing for.
If the calling script sets a variable:
BEING_SOURCED_FROM_SOMEWHERE <- TRUE
then the called script can check for it:
function1 <- function(etc,etc) {}
function2 <- function(etc,etc) {}
if (! exists("BEING_SOURCED_FROM_SOMEWHERE")) {
library(optparse)
# ...
}
I don't like it. It isn't as flexible as python's
if __name__ == "__main__":
import optparse
# ...
But I think I dislike it less than your use of save
and load
for function definitions.
run script from CLI but prevent running when included
You can test if $argv[0] == __FILE__
to see if the file called form the command line is the same as the included file.
class foo {
public function __construct() {
// Output Hello World if this file was called directly from the command line
// Edit: Probably need to use realpath() here as well..
if (isset($argv) && realpath($argv[0]) == __FILE__) {
echo("Hello world");
}
}
}
How to get a batch file only processed if it's called from another batch file?
I cannot think of any way that would prevent the bare "run" of the called script. Possibly that might only be done using NTFS permissions.
What you can do quickly is something like this:
MOTHERBATCH.bat
call compileData.bat SomePASSPHRASE
compileData.bat
@echo off
if not "%1"=="SomePASSPHRASE" (
echo "You can not run this script directly, please run MOTHERSCRIPT.bat."
exit /B 1
)
echo "Passphrase is correct, code is executed..."
Detecting if script executed from command line in Racket?
Racket has the concept of main
submodules. You can read about them in the Racket Guide section entitled Main and Test Submodules. They do precisely what you want—when a file is run directly using racket
or DrRacket, the main submodule is executed. If a file is used by another file using require
, the main submodule is not run.
The Racket equivalent of your Python program would be the following:
#lang racket
(define (foo)
"foo!")
(module+ main
(foo))
Run function from the command line
With the -c
(command) argument (assuming your file is named foo.py
):
$ python -c 'import foo; print foo.hello()'
Alternatively, if you don't care about namespace pollution:
$ python -c 'from foo import *; print hello()'
And the middle ground:
$ python -c 'from foo import hello; print hello()'
Run function in script from command line (Node JS)
No comment on why you want to do this, or what might be a more standard practice: here is a solution to your question.... Keep in mind that the type of quotes required by your command line may vary.
In your db.js
, export the init
function. There are many ways, but for example:
module.exports.init = function () {
console.log('hi');
};
Then call it like this, assuming your db.js
is in the same directory as your command prompt:
node -e 'require("./db").init()'
If your db.js
were a module db.mjs
, use a dynamic import to load the module:
node -e 'import("./db.mjs").then( loadedModule => loadedModule.init() )'
To other readers, the OP's init
function could have been called anything, it is not important, it is just the specific name used in the question.
Related Topics
Trying to Understand Use of Self.Method_Name VS. Classname.Method_Name in Ruby
Rails 4 Update Nested Attributes
How to Find Best Matching Element in Array of Numbers
Ruby Amazon S3 Access Denied When Listing Buckets
Ruby Operator Overloading Question
Rails Way to Detect Mobile Device
Rails Two-Legged Oauth Provider
Best Way to Handle Data Attributes in Slim
Limiting Characters/Words in View - Ruby on Rails
Rails Change Routing of Submit in Form_For
What Is the Purpose of a 'Transient Do' Block in Factorybot Factories
How to Set a Request.Referrer Inside My Rspec
How to Push Keys and Values into an Empty Hash W/ Ruby
What's the Difference Between "=" & "=>" and "@Variable", "@@Variable" and ":Variable" in Ruby