os
This module contains basic operating system facilities like retrieving environment variables, reading command line arguments, working with directories, running shell commands, etc.
import os let myFile = "/path/to/my/file.nim" let pathSplit = splitPath(myFile) assert pathSplit.head == "/path/to/my" assert pathSplit.tail == "file.nim" assert parentDir(myFile) == "/path/to/my" let fileSplit = splitFile(myFile) assert fileSplit.dir == "/path/to/my" assert fileSplit.name == "file" assert fileSplit.ext == ".nim" assert myFile.changeFileExt("c") == "/path/to/my/file.c"
See also:
- osproc module for process communication beyond execShellCmd proc
- parseopt module for command-line parser beyond parseCmdLine proc
- uri module
- distros module
- dynlib module
- streams module
Imports
Types
ReadEnvEffect = object of ReadIOEffect
- Effect that denotes a read from an environment variable. Source Edit
WriteEnvEffect = object of WriteIOEffect
- Effect that denotes a write to an environment variable. Source Edit
ReadDirEffect = object of ReadIOEffect
- Effect that denotes a read operation from the directory structure. Source Edit
WriteDirEffect = object of WriteIOEffect
- Effect that denotes a write operation to the directory structure. Source Edit
OSErrorCode = distinct int32
- Specifies an OS Error Code. Source Edit
FilePermission = enum fpUserExec, ## execute access for the file owner fpUserWrite, ## write access for the file owner fpUserRead, ## read access for the file owner fpGroupExec, ## execute access for the group fpGroupWrite, ## write access for the group fpGroupRead, ## read access for the group fpOthersExec, ## execute access for others fpOthersWrite, ## write access for others fpOthersRead ## read access for others
-
File access permission, modelled after UNIX.
See also:
Source Edit PathComponent = enum pcFile, ## path refers to a file pcLinkToFile, ## path refers to a symbolic link to a file pcDir, ## path refers to a directory pcLinkToDir ## path refers to a symbolic link to a directory
-
Enumeration specifying a path component.
See also:
Source Edit DeviceId = Dev
- Source Edit
FileId = Ino
- Source Edit
FileInfo = object id*: tuple[device: DeviceId, file: FileId] ## Device and file id. kind*: PathComponent ## Kind of file object - directory, symlink, etc. size*: BiggestInt ## Size of file. permissions*: set[FilePermission] ## File permissions linkCount*: BiggestInt ## Number of hard links the file object has. lastAccessTime*: times.Time ## Time file was last accessed. lastWriteTime*: times.Time ## Time file was last modified/written to. creationTime*: times.Time ## Time file was created. Not supported on all systems!
-
Contains information associated with a file object.
See also:
Source Edit
Consts
invalidFilenameChars = {'/', '\\', ':', '*', '?', '\"', '<', '>', '|', '^', '\x00'}
- Characters that may produce invalid filenames across Linux, Windows, Mac, etc. You can check if your filename contains these char and strip them for safety. Mac bans
':'
, Linux bans'/'
, Windows bans all others. Source Edit invalidFilenames = ["CON", "PRN", "AUX", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"]
- Filenames that may be invalid across Linux, Windows, Mac, etc. You can check if your filename match these and rename it for safety (Currently all invalid filenames are from Windows only). Source Edit
doslikeFileSystem = false
- Source Edit
CurDir = '.'
-
The constant character used by the operating system to refer to the current directory.
For example:
Source Edit'.'
for POSIX or':'
for the classic Macintosh. ParDir = ".."
-
The constant string used by the operating system to refer to the parent directory.
For example:
Source Edit".."
for POSIX or"::"
for the classic Macintosh. DirSep = '/'
- The character used by the operating system to separate pathname components, for example:
'/'
for POSIX,':'
for the classic Macintosh, and'\'
on Windows. Source Edit AltSep = '/'
- An alternative character used by the operating system to separate pathname components, or the same as DirSep if only one separator character exists. This is set to
'/'
on Windows systems where DirSep is a backslash ('\'
). Source Edit PathSep = ':'
- The character conventionally used by the operating system to separate search patch components (as in PATH), such as
':'
for POSIX or';'
for Windows. Source Edit FileSystemCaseSensitive = true
- True if the file system is case sensitive, false otherwise. Used by cmpPaths proc to compare filenames properly. Source Edit
ExeExt = ""
- The file extension of native executables. For example:
""
for POSIX,"exe"
on Windows (without a dot). Source Edit ScriptExt = ""
- The file extension of a script file. For example:
""
for POSIX,"bat"
on Windows. Source Edit DynlibFormat = "lib$1.so"
- The format string to turn a filename into a DLL file (also called on some operating systems). Source Edit
ExtSep = '.'
- The character which separates the base filename from the extension; for example, the
'.'
inos.nim
. Source Edit ExeExts = [""]
- Platform specific file extension for executables. On Windows
["exe", "cmd", "bat"]
, on Posix[""]
. Source Edit
Procs
proc normalizePathEnd(path: var string; trailingSep = false) {...}{.raises: [], tags: [].}
- Ensures
path
has exactly 0 or 1 trailingDirSep
, depending ontrailingSep
, and taking care of edge cases: it preservers whether a path is absolute or relative, and makes sure trailing sep isDirSep
, notAltSep
. Trailing/.
are compressed, see examples. Source Edit proc normalizePathEnd(path: string; trailingSep = false): string {...}{.raises: [], tags: [].}
- outplace overload
Example:
when defined(posix): assert normalizePathEnd("/lib//.//", trailingSep = true) == "/lib/" assert normalizePathEnd("lib/./.", trailingSep = false) == "lib" assert normalizePathEnd(".//./.", trailingSep = false) == "." assert normalizePathEnd("", trailingSep = true) == "" # not / ! assert normalizePathEnd("/", trailingSep = false) == "/" # not "" !
Source Edit proc joinPath(head, tail: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Joins two directory names to one.
returns normalized path concatenation of
head
andtail
, preserving whether or nottail
has a trailing slash (or, if tail if empty, whether head has one).See also:
Example:
when defined(posix): assert joinPath("usr", "lib") == "usr/lib" assert joinPath("usr", "lib/") == "usr/lib/" assert joinPath("usr", "") == "usr" assert joinPath("usr/", "") == "usr/" assert joinPath("", "") == "" assert joinPath("", "lib") == "lib" assert joinPath("", "/lib") == "/lib" assert joinPath("usr/", "/lib") == "usr/lib" assert joinPath("usr/lib", "../bin") == "usr/bin"
Source Edit proc joinPath(parts: varargs[string]): string {...}{.noSideEffect, gcsafe, extern: "nos$1OpenArray", raises: [], tags: [].}
-
The same as joinPath(head, tail) proc, but works with any number of directory parts.
You need to pass at least one element or the proc will assert in debug builds and crash on release builds.
See also:
Example:
when defined(posix): assert joinPath("a") == "a" assert joinPath("a", "b", "c") == "a/b/c" assert joinPath("usr/lib", "../../var", "log") == "var/log"
Source Edit proc `/`(head, tail: string): string {...}{.noSideEffect, raises: [], tags: [].}
-
The same as joinPath(head, tail) proc.
See also:
- /../ proc
- joinPath(head, tail) proc
- joinPath(varargs) proc
- splitPath proc
- uri.combine proc
- uri./ proc
Example:
when defined(posix): assert "usr" / "" == "usr" assert "" / "lib" == "lib" assert "" / "/lib" == "/lib" assert "usr/" / "/lib/" == "usr/lib/" assert "usr" / "lib" / "../bin" == "usr/bin"
Source Edit proc splitPath(path: string): tuple[head, tail: string] {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Splits a directory into
(head, tail)
tuple, so thathead / tail == path
(except for edge cases like "/usr").See also:
Example:
assert splitPath("usr/local/bin") == ("usr/local", "bin") assert splitPath("usr/local/bin/") == ("usr/local/bin", "") assert splitPath("/bin/") == ("/bin", "") when (NimMajor, NimMinor) <= (1, 0): assert splitPath("/bin") == ("", "bin") else: assert splitPath("/bin") == ("/", "bin") assert splitPath("bin") == ("", "bin") assert splitPath("") == ("", "")
Source Edit proc isAbsolute(path: string): bool {...}{.gcsafe, noSideEffect, extern: "nos$1", raises: [], tags: [].}
-
Checks whether a given
path
is absolute.On Windows, network paths are considered absolute too.
Example:
assert not "".isAbsolute assert not ".".isAbsolute when defined(posix): assert "/".isAbsolute assert not "a/".isAbsolute assert "/a/".isAbsolute
Source Edit proc relativePath(path, base: string; sep = DirSep): string {...}{.gcsafe, extern: "nos$1", raises: [Exception], tags: [RootEffect].}
-
Converts
path
to a path relative tobase
.The
sep
(default: DirSep) is used for the path normalizations, this can be useful to ensure the relative path only contains'/'
so that it can be used for URL constructions.On windows, if a root of
path
and a root ofbase
are different, returnspath
as is because it is impossible to make a relative path. That means an absolute path can be returned.See also:
Example:
assert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim" assert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim" assert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim" assert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" assert relativePath("", "/users/moo", '/') == "" assert relativePath("foo", ".", '/') == "foo" assert relativePath("foo", "foo", '/') == "."
Source Edit proc isRelativeTo(path: string; base: string): bool {...}{.raises: [Exception], tags: [RootEffect].}
- Returns true if
path
is relative tobase
.Example:
doAssert isRelativeTo("./foo//bar", "foo") doAssert isRelativeTo("foo/bar", ".") doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim") doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim")
Source Edit proc parentDir(path: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Returns the parent directory of
path
.This is similar to
splitPath(path).head
whenpath
doesn't end in a dir separator, but also takes care of path normalizations. The remainder can be obtained with lastPathPart(path) proc.See also:
Example:
assert parentDir("") == "" when defined(posix): assert parentDir("/usr/local/bin") == "/usr/local" assert parentDir("foo/bar//") == "foo" assert parentDir("//foo//bar//.") == "/foo" assert parentDir("./foo") == "." assert parentDir("/./foo//./") == "/" assert parentDir("a//./") == "." assert parentDir("a/b/c/..") == "a"
Source Edit proc tailDir(path: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Returns the tail part of
path
.See also:
Example:
assert tailDir("/bin") == "bin" assert tailDir("bin") == "" assert tailDir("bin/") == "" assert tailDir("/usr/local/bin") == "usr/local/bin" assert tailDir("//usr//local//bin//") == "usr//local//bin//" assert tailDir("./usr/local/bin") == "usr/local/bin" assert tailDir("usr/local/bin") == "local/bin"
Source Edit proc isRootDir(path: string): bool {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
- Checks whether a given
path
is a root directory.Example:
assert isRootDir("") assert isRootDir(".") assert isRootDir("/") assert isRootDir("a") assert not isRootDir("/a") assert not isRootDir("a/b/c")
Source Edit proc `/../`(head, tail: string): string {...}{.noSideEffect, raises: [], tags: [].}
-
The same as
parentDir(head) / tail
, unless there is no parent directory. Thenhead / tail
is performed instead.See also:
Example:
when defined(posix): assert "a/b/c" /../ "d/e" == "a/b/d/e" assert "a" /../ "d/e" == "a/d/e"
Source Edit proc searchExtPos(path: string): int {...}{.raises: [], tags: [].}
-
Returns index of the
'.'
char inpath
if it signifies the beginning of extension. Returns -1 otherwise.See also:
Example:
assert searchExtPos("a/b/c") == -1 assert searchExtPos("c.nim") == 1 assert searchExtPos("a/b/c.nim") == 5 assert searchExtPos("a.b.c.nim") == 5
Source Edit proc splitFile(path: string): tuple[dir, name, ext: string] {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Splits a filename into
(dir, name, extension)
tuple.dir
does not end in DirSep unless it's/
.extension
includes the leading dot.If
path
has no extension,ext
is the empty string. Ifpath
has no directory component,dir
is the empty string. Ifpath
has no filename component,name
andext
are empty strings.See also:
Example:
var (dir, name, ext) = splitFile("usr/local/nimc.html") assert dir == "usr/local" assert name == "nimc" assert ext == ".html" (dir, name, ext) = splitFile("/usr/local/os") assert dir == "/usr/local" assert name == "os" assert ext == "" (dir, name, ext) = splitFile("/usr/local/") assert dir == "/usr/local" assert name == "" assert ext == "" (dir, name, ext) = splitFile("/tmp.txt") assert dir == "/" assert name == "tmp" assert ext == ".txt"
Source Edit proc extractFilename(path: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Extracts the filename of a given
path
.This is the same as
name & ext
from splitFile(path) proc.See also:
Example:
assert extractFilename("foo/bar/") == "" assert extractFilename("foo/bar") == "bar" assert extractFilename("foo/bar.baz") == "bar.baz"
Source Edit proc lastPathPart(path: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Like extractFilename proc, but ignores trailing dir separator; aka: baseName in some other languages.
See also:
Example:
assert lastPathPart("foo/bar/") == "bar" assert lastPathPart("foo/bar") == "bar"
Source Edit proc changeFileExt(filename, ext: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Changes the file extension to
ext
.If the
filename
has no extension,ext
will be added. Ifext
== "" then any extension is removed.Ext
should be given without the leading'.'
, because some filesystems may use a different character. (Although I know of none such beast.)See also:
Example:
assert changeFileExt("foo.bar", "baz") == "foo.baz" assert changeFileExt("foo.bar", "") == "foo" assert changeFileExt("foo", "baz") == "foo.baz"
Source Edit proc addFileExt(filename, ext: string): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Adds the file extension
ext
tofilename
, unlessfilename
already has an extension.Ext
should be given without the leading'.'
, because some filesystems may use a different character. (Although I know of none such beast.)See also:
Example:
assert addFileExt("foo.bar", "baz") == "foo.bar" assert addFileExt("foo.bar", "") == "foo.bar" assert addFileExt("foo", "baz") == "foo.baz"
Source Edit proc cmpPaths(pathA, pathB: string): int {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Compares two paths.
On a case-sensitive filesystem this is done case-sensitively otherwise case-insensitively. Returns:
0 if pathA == pathB
< 0 if pathA < pathB
> 0 if pathA > pathBExample:
when defined(macosx): assert cmpPaths("foo", "Foo") == 0 elif defined(posix): assert cmpPaths("foo", "Foo") > 0
Source Edit proc unixToNativePath(path: string; drive = ""): string {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Converts an UNIX-like path to a native one.
On an UNIX system this does nothing. Else it converts
'/'
,'.'
,'..'
to the appropriate things.On systems with a concept of "drives",
Source Editdrive
is used to determine which drive label to use during absolute path conversion.drive
defaults to the drive of the current working directory, and is ignored on systems that do not have a concept of "drives". proc `==`(err1, err2: OSErrorCode): bool {...}{.borrow.}
- Source Edit
proc `$`(err: OSErrorCode): string {...}{.borrow.}
- Source Edit
proc osErrorMsg(errorCode: OSErrorCode): string {...}{.raises: [], tags: [].}
-
Converts an OS error code into a human readable string.
The error code can be retrieved using the osLastError proc.
If conversion fails, or
errorCode
is0
then""
will be returned.On Windows, the
-d:useWinAnsi
compilation flag can be used to make this procedure use the non-unicode Win API calls to retrieve the message.See also:
Example:
when defined(linux): assert osErrorMsg(OSErrorCode(0)) == "" assert osErrorMsg(OSErrorCode(1)) == "Operation not permitted" assert osErrorMsg(OSErrorCode(2)) == "No such file or directory"
Source Edit proc newOSError(errorCode: OSErrorCode; additionalInfo = ""): owned(ref OSError) {...}{. noinline, raises: [], tags: [].}
-
Creates a new OSError exception.
The
errorCode
will determine the message, osErrorMsg proc will be used to get this message.The error code can be retrieved using the osLastError proc.
If the error code is
0
or an error message could not be retrieved, the messageunknown OS error
will be used.See also:
Source Edit proc raiseOSError(errorCode: OSErrorCode; additionalInfo = "") {...}{.noinline, raises: [OSError], tags: [].}
-
Raises an OSError exception.
Read the description of the newOSError proc to learn how the exception object is created.
Source Edit proc osLastError(): OSErrorCode {...}{.sideEffect, raises: [], tags: [].}
-
Retrieves the last operating system error code.
This procedure is useful in the event when an OS call fails. In that case this procedure will return the error code describing the reason why the OS call failed. The
OSErrorMsg
procedure can then be used to convert this code into a string.Warning: The behaviour of this procedure varies between Windows and POSIX systems. On Windows some OS calls can reset the error code to
0
causing this procedure to return0
. It is therefore advised to call this procedure immediately after an OS call fails. On POSIX systems this is not a problem.See also:
Source Edit proc getEnv(key: string; default = ""): TaintedString {...}{.tags: [ReadEnvEffect], raises: [].}
-
Returns the value of the environment variable named
key
.If the variable does not exist,
""
is returned. To distinguish whether a variable exists or it's value is just""
, call existsEnv(key) proc.See also:
Example:
assert getEnv("unknownEnv") == "" assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist"
Source Edit proc existsEnv(key: string): bool {...}{.tags: [ReadEnvEffect], raises: [].}
-
Checks whether the environment variable named
key
exists. Returns true if it exists, false otherwise.See also:
Example:
assert not existsEnv("unknownEnv")
Source Edit proc putEnv(key, val: string) {...}{.tags: [WriteEnvEffect], raises: [OSError].}
-
Sets the value of the environment variable named
key
toval
. If an error occurs,OSError
is raised.See also:
Source Edit proc delEnv(key: string) {...}{.tags: [WriteEnvEffect], raises: [OSError].}
-
Deletes the environment variable named
key
. If an error occurs,OSError
is raised.See also:ven
Source Edit proc getHomeDir(): string {...}{.gcsafe, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect], raises: [].}
-
Returns the home directory of the current user.
This proc is wrapped by the expandTilde proc for the convenience of processing paths coming from user configuration files.
See also:
Example:
assert getHomeDir() == expandTilde("~")
Source Edit proc getConfigDir(): string {...}{.gcsafe, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect], raises: [].}
-
Returns the config directory of the current user for applications.
On non-Windows OSs, this proc conforms to the XDG Base Directory spec. Thus, this proc returns the value of the
XDG_CONFIG_HOME
environment variable if it is set, otherwise it returns the default configuration directory ("~/.config/").An OS-dependent trailing slash is always present at the end of the returned string:
\
on Windows and/
on all other OSs.See also:
Source Edit proc getTempDir(): string {...}{.gcsafe, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect], raises: [].}
-
Returns the temporary directory of the current user for applications to save temporary files in.
Please do not use this: On Android, it currently returns
getHomeDir()
, and on other Unix based systems it can cause security problems too. That said, you can override this implementation by adding-d:tempDir=mytempname
to your compiler invocation.See also:
Source Edit proc expandTilde(path: string): string {...}{.tags: [ReadEnvEffect, ReadIOEffect], raises: [].}
-
Expands
~
or a path starting with~/
to a full path, replacing~
with getHomeDir() (otherwise returnspath
unmodified).Windows: this is still supported despite Windows platform not having this convention; also, both
~/
and~\
are handled.Warning:
~bob
and~bob/
are not yet handled correctly.See also:
Example:
assert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg" assert expandTilde("~/foo/bar") == getHomeDir() / "foo/bar" assert expandTilde("/foo/bar") == "/foo/bar"
Source Edit proc quoteShellWindows(s: string): string {...}{.noSideEffect, gcsafe, extern: "nosp$1", raises: [], tags: [].}
-
Quote
s
, so it can be safely passed to Windows API.Based on Python's
Source Editsubprocess.list2cmdline
. See this link for more details. proc quoteShellPosix(s: string): string {...}{.noSideEffect, gcsafe, extern: "nosp$1", raises: [], tags: [].}
- Quote
s
, so it can be safely passed to POSIX shell. Based on Python'spipes.quote
. Source Edit proc quoteShell(s: string): string {...}{.noSideEffect, gcsafe, extern: "nosp$1", raises: [], tags: [].}
-
Quote
s
, so it can be safely passed to shell.When on Windows, it calls quoteShellWindows proc. Otherwise, calls quoteShellPosix proc.
Source Edit proc quoteShellCommand(args: openArray[string]): string {...}{.raises: [], tags: [].}
- Concatenates and quotes shell arguments
args
.Example:
when defined(posix): assert quoteShellCommand(["aaa", "", "c d"]) == "aaa '' 'c d'" when defined(windows): assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\""
Source Edit proc fileExists(filename: string): bool {...}{.gcsafe, extern: "nos$1", tags: [ReadDirEffect], raises: [].}
-
Returns true if
filename
exists and is a regular file or symlink.Directories, device files, named pipes and sockets return false.
See also:
Source Edit proc dirExists(dir: string): bool {...}{.gcsafe, extern: "nos$1", tags: [ReadDirEffect], raises: [].}
-
Returns true if the directory
dir
exists. Ifdir
is a file, false is returned. Follows symlinks.See also:
Source Edit proc symlinkExists(link: string): bool {...}{.gcsafe, extern: "nos$1", tags: [ReadDirEffect], raises: [].}
-
Returns true if the symlink
link
exists. Will return true regardless of whether the link points to a directory or file.See also:
Source Edit proc findExe(exe: string; followSymlinks: bool = true; extensions: openArray[string] = ExeExts): string {...}{. tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect], raises: [OSError].}
-
Searches for
exe
in the current working directory and then in directories listed in thePATH
environment variable.Returns
""
if theexe
cannot be found.exe
is added the ExeExts file extensions if it has none.If the system supports symlinks it also resolves them until it meets the actual file. This behavior can be disabled if desired by setting
Source EditfollowSymlinks = false
. proc getLastModificationTime(file: string): times.Time {...}{.gcsafe, extern: "nos$1", raises: [OSError], tags: [].}
-
Returns the
file
's last modification time.See also:
Source Edit proc getLastAccessTime(file: string): times.Time {...}{.gcsafe, extern: "nos$1", raises: [OSError], tags: [].}
-
Returns the
file
's last read or write access time.See also:
Source Edit proc getCreationTime(file: string): times.Time {...}{.gcsafe, extern: "nos$1", raises: [OSError], tags: [].}
-
Returns the
file
's creation time.Note: Under POSIX OS's, the returned time may actually be the time at which the file's attribute's were last modified. See here for details.
See also:
Source Edit proc fileNewer(a, b: string): bool {...}{.gcsafe, extern: "nos$1", raises: [OSError], tags: [].}
-
Returns true if the file
a
is newer than fileb
, i.e. ifa
's modification time is later thanb
's.See also:
Source Edit proc getCurrentDir(): string {...}{.gcsafe, extern: "nos$1", tags: [], raises: [OSError].}
-
Returns the current working directory i.e. where the built binary is run.
So the path returned by this proc is determined at run time.
See also:
- getHomeDir proc
- getConfigDir proc
- getTempDir proc
- setCurrentDir proc
- currentSourcePath template
- getProjectPath proc
proc setCurrentDir(newDir: string) {...}{.inline, tags: [], raises: [OSError].}
-
Sets the current working directory;
OSError
is raised ifnewDir
cannot been set.See also:
Source Edit proc absolutePath(path: string; root = getCurrentDir()): string {...}{. raises: [ValueError], tags: [].}
-
Returns the absolute path of
path
, rooted atroot
(which must be absolute; default: current directory). Ifpath
is absolute, return it, ignoringroot
.See also:
Example:
assert absolutePath("a") == getCurrentDir() / "a"
Source Edit proc normalizeExe(file: var string) {...}{.raises: [], tags: [].}
- on posix, prepends
./
iffile
doesn't contain/
and is not"", ".", ".."
.Example:
import sugar when defined(posix): doAssert "foo".dup(normalizeExe) == "./foo" doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar" doAssert "".dup(normalizeExe) == ""
Source Edit proc normalizePath(path: var string) {...}{.gcsafe, extern: "nos$1", tags: [], raises: [].}
-
Normalize a path.
Consecutive directory separators are collapsed, including an initial double slash.
On relative paths, double dot (
..
) sequences are collapsed if possible. On absolute paths they are always collapsed.Warning: URL-encoded and Unicode attempts at directory traversal are not detected. Triple dot is not handled.
See also:
- absolutePath proc
- normalizedPath proc for outplace version
- normalizeExe proc
Example:
when defined(posix): var a = "a///b//..//c///d" a.normalizePath() assert a == "a/c/d"
Source Edit proc normalizedPath(path: string): string {...}{.gcsafe, extern: "nos$1", tags: [], raises: [].}
-
Returns a normalized path for the current OS.
See also:
- absolutePath proc
- normalizePath proc for the in-place version
Example:
when defined(posix): assert normalizedPath("a///b//..//c///d") == "a/c/d"
Source Edit proc sameFile(path1, path2: string): bool {...}{.gcsafe, extern: "nos$1", tags: [ReadDirEffect], raises: [OSError].}
-
Returns true if both pathname arguments refer to the same physical file or directory.
Raises
OSError
if any of the files does not exist or information about it can not be obtained.This proc will return true if given two alternative hard-linked or sym-linked paths to the same file or directory.
See also:
Source Edit proc sameFileContent(path1, path2: string): bool {...}{.gcsafe, extern: "nos$1", tags: [ReadIOEffect], raises: [IOError].}
-
Returns true if both pathname arguments refer to files with identical binary content.
See also:
Source Edit proc getFilePermissions(filename: string): set[FilePermission] {...}{.gcsafe, extern: "nos$1", tags: [ReadDirEffect], raises: [OSError].}
-
Retrieves file permissions for
filename
.OSError
is raised in case of an error. On Windows, only thereadonly
flag is checked, every other permission is available in any case.See also:
Source Edit proc setFilePermissions(filename: string; permissions: set[FilePermission]) {...}{. gcsafe, extern: "nos$1", tags: [WriteDirEffect], raises: [OSError].}
-
Sets the file permissions for
filename
.OSError
is raised in case of an error. On Windows, only thereadonly
flag is changed, depending onfpUserWrite
permission.See also:
Source Edit proc copyFile(source, dest: string) {...}{.gcsafe, extern: "nos$1", tags: [ReadIOEffect, WriteIOEffect], raises: [OSError, IOError].}
-
Copies a file from
source
todest
, wheredest.parentDir
must exist.If this fails,
OSError
is raised.On the Windows platform this proc will copy the source file's attributes into dest.
On other platforms you need to use getFilePermissions and setFilePermissions procs to copy them by hand (or use the convenience copyFileWithPermissions proc), otherwise
dest
will inherit the default permissions of a newly created file for the user.If
dest
already exists, the file attributes will be preserved and the content overwritten.See also:
Source Edit proc copyFileToDir(source, dir: string) {...}{. raises: [ValueError, OSError, IOError], tags: [ReadIOEffect, WriteIOEffect].}
- Copies a file
source
into directorydir
, which must exist. Source Edit proc tryRemoveFile(file: string): bool {...}{.gcsafe, extern: "nos$1", tags: [WriteDirEffect], raises: [].}
-
Removes the
file
.If this fails, returns
false
. This does not fail if the file never existed in the first place.On Windows, ignores the read-only attribute.
See also:
Source Edit proc removeFile(file: string) {...}{.gcsafe, extern: "nos$1", tags: [WriteDirEffect], raises: [OSError].}
-
Removes the
file
.If this fails,
OSError
is raised. This does not fail if the file never existed in the first place.On Windows, ignores the read-only attribute.
See also:
Source Edit proc moveFile(source, dest: string) {...}{.gcsafe, extern: "nos$1", tags: [ReadIOEffect, WriteIOEffect], raises: [OSError, IOError, Exception].}
-
Moves a file from
source
todest
.If this fails,
OSError
is raised. Ifdest
already exists, it will be overwritten.Can be used to rename files.
See also:
Source Edit proc exitStatusLikeShell(status: cint): cint {...}{.raises: [], tags: [].}
- Converts exit code from
c_system
into a shell exit code. Source Edit proc execShellCmd(command: string): int {...}{.gcsafe, extern: "nos$1", tags: [ExecIOEffect], raises: [].}
-
Executes a shell command.
Command has the form 'program args' where args are the command line arguments given to program. The proc returns the error code of the shell when it has finished (zero if there is no error). The proc does not return until the process has finished.
To execute a program without having a shell involved, use osproc.execProcess proc.
Examples:
discard execShellCmd("ls -la")
Source Edit proc expandFilename(filename: string): string {...}{.gcsafe, extern: "nos$1", tags: [ReadDirEffect], raises: [OSError].}
-
Returns the full (absolute) path of an existing file
filename
.Raises
Source EditOSError
in case of an error. Follows symlinks. proc getCurrentCompilerExe(): string {...}{.compileTime, raises: [], tags: [].}
-
This is getAppFilename() at compile time.
Can be used to retrieve the currently executing Nim compiler from a Nim or nimscript program, or the nimble binary inside a nimble program (likewise with other binaries built from compiler API).
Source Edit proc removeDir(dir: string; checkDir = false) {...}{.gcsafe, extern: "nos$1", tags: [WriteDirEffect, ReadDirEffect], gcsafe, locks: 0, raises: [OSError].}
-
Removes the directory
dir
including all subdirectories and files indir
(recursively).If this fails,
OSError
is raised. This does not fail if the directory never existed in the first place, unlesscheckDir
= trueSee also:
- tryRemoveFile proc
- removeFile proc
- existsOrCreateDir proc
- createDir proc
- copyDir proc
- copyDirWithPermissions proc
- moveDir proc
proc existsOrCreateDir(dir: string): bool {...}{.gcsafe, extern: "nos$1", tags: [WriteDirEffect, ReadDirEffect], raises: [OSError, IOError].}
-
Check if a directory
dir
exists, and create it otherwise.Does not create parent directories (fails if parent does not exist). Returns
true
if the directory already exists, andfalse
otherwise.See also:
Source Edit proc createDir(dir: string) {...}{.gcsafe, extern: "nos$1", tags: [WriteDirEffect, ReadDirEffect], raises: [OSError, IOError].}
-
Creates the directory
dir
.The directory may contain several subdirectories that do not exist yet. The full path is created. If this fails,
OSError
is raised.It does not fail if the directory already exists because for most usages this does not indicate an error.
See also:
Source Edit proc copyDir(source, dest: string) {...}{.gcsafe, extern: "nos$1", tags: [WriteIOEffect, ReadIOEffect], gcsafe, locks: 0, raises: [OSError, IOError].}
-
Copies a directory from
source
todest
.If this fails,
OSError
is raised.On the Windows platform this proc will copy the attributes from
source
intodest
.On other platforms created files and directories will inherit the default permissions of a newly created file/directory for the user. Use copyDirWithPermissions proc to preserve attributes recursively on these platforms.
See also:
- copyDirWithPermissions proc
- copyFile proc
- copyFileWithPermissions proc
- removeDir proc
- existsOrCreateDir proc
- createDir proc
- moveDir proc
proc moveDir(source, dest: string) {...}{.tags: [ReadIOEffect, WriteIOEffect], raises: [OSError, IOError].}
-
Moves a directory from
source
todest
.If this fails,
OSError
is raised.See also:
- moveFile proc
- copyDir proc
- copyDirWithPermissions proc
- removeDir proc
- existsOrCreateDir proc
- createDir proc
proc createSymlink(src, dest: string) {...}{.raises: [OSError], tags: [].}
-
Create a symbolic link at
dest
which points to the item specified bysrc
. On most operating systems, will fail if a link already exists.Warning: Some OS's (such as Microsoft Windows) restrict the creation of symlinks to root users (administrators).
See also:
Source Edit proc createHardlink(src, dest: string) {...}{.raises: [OSError], tags: [].}
-
Create a hard link at
dest
which points to the item specified bysrc
.Warning: Some OS's restrict the creation of hard links to root users (administrators).
See also:
Source Edit proc copyFileWithPermissions(source, dest: string; ignorePermissionErrors = true) {...}{. raises: [OSError, IOError, Exception], tags: [ReadIOEffect, WriteIOEffect, WriteDirEffect, ReadDirEffect].}
-
Copies a file from
source
todest
preserving file permissions.This is a wrapper proc around copyFile, getFilePermissions and setFilePermissions procs on non-Windows platforms.
On Windows this proc is just a wrapper for copyFile proc since that proc already copies attributes.
On non-Windows systems permissions are copied after the file itself has been copied, which won't happen atomically and could lead to a race condition. If
ignorePermissionErrors
is true (default), errors while reading/setting file attributes will be ignored, otherwise will raiseOSError
.See also:
- copyFile proc
- copyDir proc
- tryRemoveFile proc
- removeFile proc
- moveFile proc
- copyDirWithPermissions proc
proc copyDirWithPermissions(source, dest: string; ignorePermissionErrors = true) {...}{. gcsafe, extern: "nos$1", tags: [WriteIOEffect, ReadIOEffect], gcsafe, locks: 0, raises: [OSError, IOError, Exception].}
-
Copies a directory from
source
todest
preserving file permissions.If this fails,
OSError
is raised. This is a wrapper proc around copyDir and copyFileWithPermissions procs on non-Windows platforms.On Windows this proc is just a wrapper for copyDir proc since that proc already copies attributes.
On non-Windows systems permissions are copied after the file or directory itself has been copied, which won't happen atomically and could lead to a race condition. If
ignorePermissionErrors
is true (default), errors while reading/setting file attributes will be ignored, otherwise will raiseOSError
.See also:
- copyDir proc
- copyFile proc
- copyFileWithPermissions proc
- removeDir proc
- moveDir proc
- existsOrCreateDir proc
- createDir proc
proc inclFilePermissions(filename: string; permissions: set[FilePermission]) {...}{. gcsafe, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], raises: [OSError].}
- A convenience proc for:
setFilePermissions(filename, getFilePermissions(filename)+permissions)
Source Edit proc exclFilePermissions(filename: string; permissions: set[FilePermission]) {...}{. gcsafe, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], raises: [OSError].}
- A convenience proc for:
setFilePermissions(filename, getFilePermissions(filename)-permissions)
Source Edit proc expandSymlink(symlinkPath: string): string {...}{.raises: [OSError], tags: [].}
-
Returns a string representing the path to which the symbolic link points.
On Windows this is a noop,
symlinkPath
is simply returned.See also:
Source Edit proc parseCmdLine(c: string): seq[string] {...}{.noSideEffect, gcsafe, extern: "nos$1", raises: [], tags: [].}
-
Splits a command line into several components.
Note: This proc is only occasionally useful, better use the parseopt module.
On Windows, it uses the following parsing rules:
- Arguments are delimited by white space, which is either a space or a tab.
- The caret character (^) is not recognized as an escape character or delimiter. The character is handled completely by the command-line parser in the operating system before being passed to the argv array in the program.
- A string surrounded by double quotation marks ("string") is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument.
- A double quotation mark preceded by a backslash (") is interpreted as a literal double quotation mark character (").
- Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
- If an even number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is interpreted as a string delimiter.
- If an odd number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is "escaped" by the remaining backslash, causing a literal double quotation mark (") to be placed in argv.
On Posix systems, it uses the following parsing rules: Components are separated by whitespace unless the whitespace occurs within
"
or'
quotes.See also:
Source Edit proc paramCount(): int {...}{.tags: [ReadIOEffect], raises: [].}
-
Returns the number of command line arguments given to the application.
Unlike argc in C, if your binary was called without parameters this will return zero. You can query each individual parameter with paramStr proc or retrieve all of them in one go with commandLineParams proc.
Availability: When generating a dynamic library (see
--app:lib
) on Posix this proc is not defined. Test for availability using declared().See also:
Examples:
when declared(paramCount): # Use paramCount() here else: # Do something else!
Source Edit proc paramStr(i: int): TaintedString {...}{.tags: [ReadIOEffect], raises: [].}
-
Returns the
i
-th command line argument given to the application.i
should be in the range1..paramCount()
, theIndexDefect
exception will be raised for invalid values. Instead of iterating over paramCount() with this proc you can call the convenience commandLineParams().Similarly to argv in C, it is possible to call
paramStr(0)
but this will return OS specific contents (usually the name of the invoked executable). You should avoid this and call getAppFilename() instead.Availability: When generating a dynamic library (see
--app:lib
) on Posix this proc is not defined. Test for availability using declared().See also:
Examples:
when declared(paramStr): # Use paramStr() here else: # Do something else!
Source Edit proc commandLineParams(): seq[TaintedString] {...}{.raises: [], tags: [ReadIOEffect].}
-
Convenience proc which returns the command line parameters.
This returns only the parameters. If you want to get the application executable filename, call getAppFilename().
Availability: On Posix there is no portable way to get the command line from a DLL and thus the proc isn't defined in this environment. You can test for its availability with declared().
See also:
Examples:
when declared(commandLineParams): # Use commandLineParams() here else: # Do something else!
Source Edit proc getAppFilename(): string {...}{.gcsafe, extern: "nos$1", tags: [ReadIOEffect], raises: [].}
-
Returns the filename of the application's executable. This proc will resolve symlinks.
See also:
Source Edit proc getAppDir(): string {...}{.gcsafe, extern: "nos$1", tags: [ReadIOEffect], raises: [].}
-
Returns the directory of the application's executable.
See also:
Source Edit proc sleep(milsecs: int) {...}{.gcsafe, extern: "nos$1", tags: [TimeEffect], raises: [].}
- Sleeps
milsecs
milliseconds. Source Edit proc getFileSize(file: string): BiggestInt {...}{.gcsafe, extern: "nos$1", tags: [ReadIOEffect], raises: [IOError, OSError].}
- Returns the file size of
file
(in bytes).OSError
is raised in case of an error. Source Edit proc getFileInfo(handle: FileHandle): FileInfo {...}{.raises: [OSError], tags: [].}
-
Retrieves file information for the file object represented by the given handle.
If the information cannot be retrieved, such as when the file handle is invalid,
OSError
is raised.See also:
Source Edit proc getFileInfo(file: File): FileInfo {...}{.raises: [IOError, OSError], tags: [].}
-
Retrieves file information for the file object.
See also:
Source Edit proc getFileInfo(path: string; followSymlink = true): FileInfo {...}{. raises: [OSError], tags: [].}
-
Retrieves file information for the file object pointed to by
path
.Due to intrinsic differences between operating systems, the information contained by the returned FileInfo object will be slightly different across platforms, and in some cases, incomplete or inaccurate.
When
followSymlink
is true (default), symlinks are followed and the information retrieved is information related to the symlink's target. Otherwise, information on the symlink itself is retrieved.If the information cannot be retrieved, such as when the path doesn't exist, or when permission restrictions prevent the program from retrieving file information,
OSError
is raised.See also:
Source Edit proc isHidden(path: string): bool {...}{.raises: [], tags: [].}
-
Determines whether
path
is hidden or not, using this reference.On Windows: returns true if it exists and its "hidden" attribute is set.
On posix: returns true if
lastPathPart(path)
starts with.
and is not.
or..
.Note: paths are not normalized to determine
isHidden
.Example:
when defined(posix): assert ".foo".isHidden assert not ".foo/bar".isHidden assert not ".".isHidden assert not "..".isHidden assert not "".isHidden assert ".foo/".isHidden
Source Edit proc getCurrentProcessId(): int {...}{.raises: [], tags: [].}
-
Return current process ID.
See also:
Source Edit proc setLastModificationTime(file: string; t: times.Time) {...}{.raises: [OSError], tags: [].}
- Sets the
file
's last modification time.OSError
is raised in case of an error. Source Edit
Funcs
func isValidFilename(filename: string; maxLen = 259.Positive): bool {...}{. raises: [], tags: [].}
-
Returns true if
filename
is valid for crossplatform use.This is useful if you want to copy or save files across Windows, Linux, Mac, etc. You can pass full paths as argument too, but func only checks filenames. It uses
invalidFilenameChars
,invalidFilenames
andmaxLen
to verify the specifiedfilename
.assert not isValidFilename(" foo") ## Leading white space assert not isValidFilename("foo ") ## Trailing white space assert not isValidFilename("foo.") ## Ends with Dot assert not isValidFilename("con.txt") ## "CON" is invalid (Windows) assert not isValidFilename("OwO:UwU") ## ":" is invalid (Mac) assert not isValidFilename("aux.bat") ## "AUX" is invalid (Windows)
Source Edit
Iterators
iterator parentDirs(path: string; fromRoot = false; inclusive = true): string {...}{. raises: [], tags: [].}
-
Walks over all parent directories of a given
path
.If
fromRoot
is true (default: false), the traversal will start from the file system root directory. Ifinclusive
is true (default), the original argument will be included in the traversal.Relative paths won't be expanded by this iterator. Instead, it will traverse only the directories appearing in the relative path.
See also:
Examples:
let g = "a/b/c" for p in g.parentDirs: echo p # a/b/c # a/b # a for p in g.parentDirs(fromRoot=true): echo p # a/ # a/b/ # a/b/c for p in g.parentDirs(inclusive=false): echo p # a/b # a
Source Edit iterator envPairs(): tuple[key, value: TaintedString] {...}{.tags: [ReadEnvEffect], raises: [].}
-
Iterate over all environments variables.
In the first component of the tuple is the name of the current variable stored, in the second its value.
See also:
Source Edit iterator walkPattern(pattern: string): string {...}{.tags: [ReadDirEffect], raises: [].}
-
Iterate over all the files and directories that match the
pattern
.On POSIX this uses the glob call.
pattern
is OS dependent, but at least the"*.ext"
notation is supported.See also:
Source Edit iterator walkFiles(pattern: string): string {...}{.tags: [ReadDirEffect], raises: [].}
-
Iterate over all the files that match the
pattern
.On POSIX this uses the glob call.
pattern
is OS dependent, but at least the"*.ext"
notation is supported.See also:
Source Edit iterator walkDirs(pattern: string): string {...}{.tags: [ReadDirEffect], raises: [].}
-
Iterate over all the directories that match the
pattern
.On POSIX this uses the glob call.
pattern
is OS dependent, but at least the"*.ext"
notation is supported.See also:
Source Edit iterator walkDir(dir: string; relative = false; checkDir = false): tuple[ kind: PathComponent, path: string] {...}{.tags: [ReadDirEffect], raises: [OSError].}
-
Walks over the directory
dir
and yields for each directory or file indir
. The component type and full path for each item are returned.Walking is not recursive. If
relative
is true (default: false) the resulting path is shortened to be relative todir
. Example: This directory structure:dirA / dirB / fileB1.txt / dirC / fileA1.txt / fileA2.txt
and this code:
for kind, path in walkDir("dirA"): echo(path)
produce this output (but not necessarily in this order!):
dirA/dirB dirA/dirC dirA/fileA1.txt dirA/fileA2.txt
See also:
Source Edit iterator walkDirRec(dir: string; yieldFilter = {pcFile}; followFilter = {pcDir}; relative = false; checkDir = false): string {...}{. tags: [ReadDirEffect], raises: [OSError].}
-
Recursively walks over the directory
dir
and yields for each file or directory indir
.If
relative
is true (default: false) the resulting path is shortened to be relative todir
, otherwise the full path is returned.Warning: Modifying the directory structure while the iterator is traversing may result in undefined behavior!
Walking is recursive.
followFilter
controls the behaviour of the iterator:yieldFilter meaning pcFile
yield real files (default) pcLinkToFile
yield symbolic links to files pcDir
yield real directories pcLinkToDir
yield symbolic links to directories followFilter meaning pcDir
follow real directories (default) pcLinkToDir
follow symbolic links to directories See also:
Source Edit
Templates
template existsFile(args: varargs[untyped]): untyped {...}{. deprecated: "use fileExists".}
- Source Edit
template existsDir(args: varargs[untyped]): untyped {...}{. deprecated: "use dirExists".}
- Source Edit
© 2006–2021 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/os.html