5
$\begingroup$

This is basically Analogue of NotebookDirectory[] for scripts (to get the directory path of my script.m)? or Write a mathematica script that returns the absolute path to its directory or How to set the relative directory so that they work both in script and in notebook and portable?, except that none of the answers given there work when my file starts with

#!/usr/bin/env wolframscript

and I run it as ./file.wls.

For example, this file:

$ cat file.wls
#!/usr/bin/env wolframscript
Print["$InputFileName: '"<>$InputFileName<>"'"];
Print["$Input: '"<>$Input<>"'"];
Print["NotebookDirectory[]: '"<>NotebookDirectory[]<>"'"];
$ ./file.wls
$InputFileName: ''
$Input: ''

FrontEndObject::notavail:
   A front end is not available; certain operations require a front end.

StringJoin::string:
   String expected at position 2 in NotebookDirectory[]: '<>$Failed<>'.
StringJoin[NotebookDirectory[]: ', $Failed, ']

$ echo |wolframscript
Wolfram Language 11.2.0 Engine for Linux x86 (64-bit)
Copyright 1988-2017 Wolfram Research, Inc.

In[1]:= In[1]:=

How do I make this work?

$\endgroup$

3 Answers 3

7
$\begingroup$

Here is a WolframScript that prints its own file name and directory:

#!/usr/bin/env wolframscript

(* Script assumptions :
    1.  User has Linux pgrep command installed
    2.  There is only one WolframScript running
    3.  Script has not changed directories, as with SetDirectory[]
    4.  Mathematica 11.0, or later
*)

pgrep = RunProcess[{"pgrep", "-a", "wolframscript"}];

scriptRelativePath = Last[StringSplit[ pgrep["StandardOutput"], " " ]];

scriptPath = ExpandFileName[ FileNameJoin[{Directory[], scriptRelativePath}] ];

scriptDirectory = DirectoryName[ scriptPath ];

scriptName = Last[FileNameSplit[ scriptPath ]];

Print[scriptPath]
Print[scriptRelativePath]
Print[scriptName]
Print[scriptDirectory]

Improvement

Using only WolframScript we can code:

#!/usr/bin/env wolframscript

(* Script assumptions :
    1.  Script has not changed directories, as with SetDirectory[]
    2.  Mathematica 11.0, or later
*)

scriptPath = ExpandFileName[First[$ScriptCommandLine]];
scriptName = Last[FileNameSplit[ scriptPath ]];

Print[scriptPath];
Print[scriptName];

The trick is to use $ScriptCommandLine.

$\endgroup$
5
  • $\begingroup$ Is there really no standard way to do this internally, without querying the OS? $\endgroup$ Dec 26, 2017 at 17:52
  • $\begingroup$ @JasonGross See the new "Improvement" section of my answer. $\endgroup$
    – LouisB
    Dec 26, 2017 at 20:09
  • $\begingroup$ scriptPath = ExpandFileName[Last[$ScriptCommandLine]]; should be scriptPath = ExpandFileName[First[$ScriptCommandLine]]; (i.e, Last should be First) $\endgroup$ Dec 27, 2017 at 4:08
  • $\begingroup$ Thank you, @ItaiSeggev ! $\endgroup$
    – LouisB
    Dec 27, 2017 at 4:58
  • $\begingroup$ This worked for me scriptPath = FileNameJoin[Drop[FileNameSplit[ $InputFileName ],-1]] $\endgroup$
    – S.V.
    Jan 2, 2020 at 2:54
3
$\begingroup$

$ScriptCommandLine is what you want. It gives the command that launched the script. As noted in the other answer, if you want an absolute file name you'll need to expand the first argument.

The fact that $InputFileName is empty if a normal wolframscript is correct. See my answer to Difference between "wolframscript -f" and "wolframscript -script"

If using $InputFileName is important to you, you can add -script to the command line, but then you run the risk that it won't run at all on Linux due to difference in handling white space. Alternatively, on Linux you can use !#/usr/bin/wolframscript -script, but this won't run on OS X or Windows Unix-like environments.

$\endgroup$
0
$\begingroup$

Indeed, NotebookDirectory[] does not work in the script environment.

In a script environment, just replace NotebookDirectory[] by Directory[].

In a script environment, the output of Directory[] is the path of the script file (or the path from where you started the wolframscript session).

If for some reason you want a command to work in both notebook and script environments, then this should work:

Quiet@If[
  NotebookDirectory[] === $Failed, 
  Directory[], 
  NotebookDirectory[]
];

Or, as suggested by @Rolf Mertig,

If[$Notebooks, NotebookDirectory[], Directory[] ]

Note: I am running WolframScript from WolframEngine 12.2.0.

$\endgroup$
1
  • 1
    $\begingroup$ If[$Notebooks, NotebookDirectory[], Directory[] ] is slightly shorter. $\endgroup$ Oct 30, 2021 at 20:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.