NAME

Sidef::Sys::Sys - System-level operations and utilities

DESCRIPTION

The Sys class provides an interface to various system-level operations, including process control, timing, I/O, object introspection, weak references, and the traditional Unix user/group/host/network/protocol/service databases. This class wraps many Perl built-in functions and provides a Sidef-friendly interface to system programming capabilities.

Sys is normally used through the pre-existing global Sys instance rather than by constructing your own (see "new").

SYNOPSIS

# Process control
var pid = Sys.fork
Sys.sleep(2)
Sys.exit(0)

# I/O operations
Sys.say("Hello, World!")
var input = Sys.readln("Enter your name: ")
Sys.printf("Welcome, %s!\n", input)

# System information
say Sys.os           # Operating system name
say Sys.user         # Current username

# File operations
Sys.open(\var fh, '<', 'file.txt')
Sys.opendir(\var dh, '/tmp')

# User/group information
var user_info = Sys.getpwnam('root')
var group_info = Sys.getgrnam('wheel')

INHERITS

Inherits methods from Sidef::Object::Object.

CONSTRUCTION

new

Sys.new

Creates a new, empty Sys object. Any arguments given are ignored — this constructor takes none. There is normally no need to call this yourself; Sidef provides a ready-made Sys instance for the whole program.

PROCESS CONTROL

fork

self.fork

Creates a child process. Returns the child's process ID (PID) to the parent process, 0 to the child process, or nil on failure.

var pid = Sys.fork

if (pid == 0) {
    say "I am the child"
    Sys.exit(0)
}
else {
    say "I am the parent, child PID: #{pid}"
    Sys.wait
}

wait

self.wait

Waits for any child process to terminate and returns its process ID, or -1 if there are no child processes to wait for.

var pid = Sys.fork

if (pid == 0) {
    Sys.exit(0)
}
else {
    var terminated_pid = Sys.wait
    say "Child #{terminated_pid} terminated"
}

exit

self.exit(code)

Terminates the program immediately with the specified exit code. An exit code of 0 typically indicates success, while non-zero values indicate various error conditions. If omitted, code defaults to 0.

Sys.exit(0)     # Success
Sys.exit(1)     # Error

kill

self.kill(signal, *list)

Sends signal to each process ID in list. signal can be a signal name (e.g. 'TERM', 'KILL', 'HUP') or number. Returns the number of processes successfully signaled.

Sys.kill('TERM', 1234)        # Terminate process 1234
Sys.kill(9, 1234, 5678)       # Kill multiple processes
Sys.kill('HUP', Sys.getppid)  # Send HUP to parent

system

self.system(*args)

Executes an external command and waits for it to complete, exactly like Perl's built-in system. Output goes directly to STDOUT/STDERR. Returns the raw child status value: 0 means the command exited successfully; any other value packs the exit code and signal information together (the actual exit code is the returned value shifted right by 8 bits).

Sys.system("ls", "-la")

var status = Sys.system("false")
if (status == 0) {
    say "Command succeeded"
}
else {
    say "Command failed with exit code #{status >> 8}"
}

Aliases: run

exec

self.exec(*args)

Replaces the current process image with the specified external command. This function does not return on success — the calling program is gone. Arguments can be a single command string or a command followed by its individual arguments.

Sys.exec("ls", "-la", "/tmp")
Sys.exec("echo 'Hello World'")

getppid

self.getppid

Returns the process ID (PID) of the parent process.

say "My parent PID is: #{Sys.getppid}"

getpgrp

self.getpgrp(pid)

Returns the process group ID for the specified process ID. If pid is omitted, returns the process group of the current process.

var pgrp = Sys.getpgrp()   # Current process group
var pgrp2 = Sys.getpgrp(1234)

setpgrp

self.setpgrp(pid, pgrp)

Sets the process group for the specified process ID. Both parameters default to 0 if omitted, which sets the current process as its own process group leader.

Sys.setpgrp(0, 0)  # Set current process as process group leader

getpriority

self.getpriority(which, who)

Returns the current priority (nice value) of a process, process group, or user. which specifies the target kind (0 = process, 1 = process group, 2 = user), and who specifies its ID.

var priority = Sys.getpriority(0, 0)  # Current process priority

setpriority

self.setpriority(which, who, priority)

Sets the priority (nice value) of a process, process group, or user. which specifies the target kind (0 = process, 1 = process group, 2 = user), who specifies its ID, and priority is the new value (lower numbers mean higher scheduling priority).

Sys.setpriority(0, 0, 10)  # Lower priority of current process

TIMING

alarm

self.alarm(sec)

Schedules a SIGALRM signal to be delivered to the process after sec seconds (fractional seconds are supported). Setting sec to 0 cancels any pending alarm. Returns a boolean: true if a previous alarm still had time remaining when this call replaced it, false otherwise (including when there was no previous alarm).

Sys.alarm(10)  # Set alarm for 10 seconds
Sys.alarm(0)   # Cancel alarm

ualarm

self.ualarm(usec)

Like "alarm", but usec is given in microseconds, allowing finer granularity. Returns a boolean: true if a previous alarm still had time remaining, false otherwise.

Sys.ualarm(500000)  # Alarm in 500,000 microseconds (0.5 seconds)

Aliases: micro_alarm

sleep

self.sleep(sec)

Suspends execution for sec seconds (fractional seconds are supported). Returns a boolean indicating whether any (nonzero) amount of time was actually slept.

Sys.sleep(5)     # Sleep for 5 seconds
Sys.sleep(0.5)   # Sleep for half a second

nanosleep

self.nanosleep(nsec)

Suspends execution for nsec nanoseconds — despite the similarly-named "sleep", this method's argument is a nanosecond count, not a (possibly fractional) second count. Returns a boolean indicating whether any (nonzero) amount of time was actually slept.

Sys.nanosleep(500_000_000)   # Sleep for 500,000,000 ns = 0.5 seconds
Sys.nanosleep(1_000_000)     # Sleep for 1,000,000 ns = 1 millisecond

Aliases: nano_sleep

usleep

self.usleep(usec)

Suspends execution for usec microseconds. Returns a boolean indicating whether any (nonzero) amount of time was actually slept.

Sys.usleep(500000)     # Sleep for 500,000 microseconds (0.5 seconds)
Sys.usleep(1000000)    # Sleep for 1,000,000 microseconds (1 second)

Aliases: micro_sleep

INPUT/OUTPUT

print

self.print(*args)

Prints the arguments to the currently selected output filehandle (default STDOUT), without appending a newline. Returns a boolean indicating success.

Sys.print("Hello")
Sys.print("Value: ", value, " at ", timestamp)

printf

self.printf(format, *args)

Formats and prints output according to a sprintf-style format string to the currently selected output filehandle. Returns a boolean indicating success.

Sys.printf("Value: %d, Name: %s\n", 42, "Alice")
Sys.printf("%.2f%%\n", percentage)

printh

self.printh(fh, *args)

Prints the arguments to the specified filehandle without appending a newline. fh may be a raw filehandle (as returned by, e.g., "select") or a Sidef filehandle-like object supporting its own print method — in the latter case, this simply delegates to fh.print(*args). Returns a boolean indicating success.

Sys.open(\var fh, '>', 'output.txt')
Sys.printh(fh, "Line 1")
Sys.printh(fh, "Line 2")
fh.close

println

self.println(*args)

Prints the arguments to the currently selected output filehandle (default STDOUT) and appends a newline. Returns a boolean indicating success.

Sys.println("Hello, World!")
Sys.println("Value: ", value)
Sys.println()  # Print empty line

Aliases: say

scanln

self.scanln(prompt)

Displays prompt (if given) and reads a single line of input from the terminal, returning it as a String with the trailing newline removed. Returns nil on end of input.

var name = Sys.scanln("Enter your name: ")
var age = Sys.scanln("Enter your age: ")

Aliases: readln, readline

read

self.read(type)
self.read(prompt, type)

Displays prompt (if given), reads a single line of input from the terminal, and constructs a new object of type from it (i.e. type.new(input)). type must be a class that accepts a raw string in its constructor, such as String or Number. Returns nil on end of input.

var name = Sys.read(String)
var count = Sys.read("How many? ", Number)

"scanln" is a thin wrapper around this that always uses String as the type.

select

self.select(fh)

Sets the specified filehandle as the default output filehandle for "print", "printf", "println", etc. Returns the previously selected filehandle, as a Sidef FileHandle object.

Sys.open(\var fh, '>', 'output.txt')
var old = Sys.select(fh)
say "This goes to the file"
Sys.select(old)
say "This goes to STDOUT"

stdin

self.stdin

Returns the standard input filehandle (STDIN).

var line = Sys.stdin.readline

stdout

self.stdout

Returns the standard output filehandle (STDOUT).

Sys.stdout.say("Hello")

stderr

self.stderr

Returns the standard error filehandle (STDERR).

Sys.stderr.say("Error message")

FILE AND DIRECTORY OPERATIONS

open

self.open(var, mode, filename)

Opens filename (converted via its to_file method) and assigns the resulting filehandle to var. mode follows the usual conventions ('<' for read, ''> for write, '>'> for append, etc.). The actual return value and supported modes are governed by the file object's own open method.

Sys.open(\var fh, '<', 'input.txt') && do {
    say fh.readline
    fh.close
}

opendir

self.opendir(var, dirname)

Opens the directory at dirname (converted via its to_dir method) and assigns the resulting directory handle to var.

Sys.opendir(\var dh, '/tmp') && do {
    while (var entry = dh.read) {
        say entry
    }
    dh.close
}

SYSTEM INFORMATION

osname

self.osname

Returns the operating system name as a string (e.g., 'linux', 'darwin', 'MSWin32', 'freebsd'), taken directly from Perl's $^O.

say Sys.osname

if (Sys.osname == 'linux') {
    say "Running on Linux"
}

Aliases: os

user

self.user

Returns the login name of the current user as a string.

say "Current user: #{Sys.user}"

Aliases: getlogin

sidef

self.sidef

Returns the absolute filesystem path of the currently running script.

say "Running: #{Sys.sidef}"

umask

self.umask(mode)

Sets the file creation mask (umask) to mode and returns the previous mask. If mode is omitted, simply returns the current mask without changing it.

var old = Sys.umask(0o022)  # Set umask to 022 (octal)
# Create files...
Sys.umask(old)              # Restore old umask

OBJECT INTROSPECTION

ref

self.ref(obj)

Returns a string describing what kind of reference obj is: the blessed class name for an object, a bare type such as 'ARRAY', 'HASH', or 'CODE' for an unblessed reference, or an empty string if obj is not a reference at all. This mirrors Perl's built-in ref function.

say Sys.ref([1, 2, 3])          # "Sidef::Types::Array::Array"
say Sys.ref(Hash())             # "Sidef::Types::Hash::Hash"
say Sys.ref(42)                 # "Sidef::Types::Number::Number"

See also "reftype" (which ignores blessing) and "class_name" (which strips the package prefix).

reftype

self.reftype(obj)

Returns the underlying storage type of a reference as a string (e.g., 'ARRAY', 'HASH', 'SCALAR', 'CODE'), ignoring any blessing — unlike "ref", this always reports the raw storage kind even for blessed objects.

say Sys.reftype([1,2,3])    # "ARRAY"
say Sys.reftype(Hash())     # "HASH"

class_name

self.class_name(obj)

Returns the short class name of the given object — the part of its full package name after the last ::.

say Sys.class_name(42)        # "Number"
say Sys.class_name("hello")   # "String"
say Sys.class_name([1,2,3])   # "Array"

defined

self.defined(obj)

Returns true if obj is defined (not nil), false otherwise.

say Sys.defined(nil)      # false
say Sys.defined(0)        # true
say Sys.defined("")       # true

refaddr

self.refaddr(obj)

Returns the memory address of the reference as a number. Useful for debugging and checking object identity.

var obj = [1, 2, 3]
say Sys.refaddr(obj)  # e.g., 140234567890123

bless

self.bless(obj, class)

Blesses obj into class, changing its type, and returns the blessed object.

var obj = Hash()
Sys.bless(obj, :MyClass)

WEAK REFERENCES

weaken

self.weaken(obj)

Converts a reference to a weak reference in place. Weak references do not prevent the referenced object from being garbage collected. Returns a boolean indicating success.

var obj = [1, 2, 3]
var ref = \obj
Sys.weaken(ref)
# obj can now be garbage collected even though ref exists

isweak

self.isweak(obj)

Returns true if the reference is weak (won't prevent garbage collection), false otherwise.

var ref = \obj
say Sys.isweak(ref)  # false
Sys.weaken(ref)
say Sys.isweak(ref)  # true

unweaken

self.unweaken(obj)

Converts a weak reference back into a strong reference in place. Returns a boolean indicating success.

Sys.weaken(ref)
Sys.unweaken(ref)  # Now strong again

ERROR HANDLING AND OUTPUT

die

self.die(*args)

Raises a fatal exception, concatenating the arguments to form the error message, and terminates the program unless caught. A trailing newline is added automatically, so Perl's usual "at FILE line N" suffix is suppressed.

Sys.die("Fatal error occurred!")
Sys.die("Error: ", error_msg, " at line ", line_num)

Aliases: raise

warn

self.warn(*args)

Prints a warning message to STDERR, concatenating the arguments to form the message. A trailing newline is added automatically. Unlike "die", this does not terminate the program.

Sys.warn("Warning: low disk space")
Sys.warn("Deprecated function used at line ", line_num)

USER AND GROUP DATABASES

These methods query the traditional Unix user and group databases (as one would with getpwnam(3)/getgrnam(3) and friends). A successful lookup returns an Array of positional fields (not a hash) — see each method below for its exact field order.

getpwnam

self.getpwnam(name)

Looks up a user by login name. On success, returns an array with fields, in order: [name, passwd, uid, gid, quota, comment, gcos], followed by the shell, i.e. [name, passwd, uid, gid, quota, comment, gcos, shell]. Note that the home directory is not included in the returned array. Returns nil if the user isn't found.

var user = Sys.getpwnam('root')
say user[0]   # name
say user[2]   # uid

getpwuid

self.getpwuid(uid)

Looks up a user by numeric user ID. Returns the same array shape as "getpwnam", or nil if not found.

var user = Sys.getpwuid(1000)
say user[0]   # name

getpwent

self.getpwent

Returns the next entry from the user database as the same array shape as "getpwnam", or nil when there are no more entries. Use "setpwent" to rewind and iterate again.

Sys.setpwent
while (var user = Sys.getpwent) {
    say user[0]
}

setpwent

self.setpwent

Resets the user database iterator to the beginning, so "getpwent" starts over from the first entry. Returns a boolean.

getgrnam

self.getgrnam(name)

Looks up a group by name. Note: due to how this lookup is currently implemented, a successful lookup returns just the group's name as a plain string (the passwd/gid/members fields are not accessible this way), while an unsuccessful lookup returns an array of mostly-undefined values rather than nil — the reverse of the not-found convention used elsewhere in this class.

var name = Sys.getgrnam('wheel')
say name   # "wheel"

getgrgid

self.getgrgid(gid)

Looks up a group by numeric group ID. See the caveat under "getgrnam" — this currently behaves the same way.

var name = Sys.getgrgid(0)

getgrent

self.getgrent

Returns the next entry from the group database. See the caveat under "getgrnam" — this currently behaves the same way. Use "setgrent" to rewind and iterate again.

Sys.setgrent
while (var group = Sys.getgrent) {
    say group
}

setgrent

self.setgrent

Resets the group database iterator to the beginning, so "getgrent" starts over from the first entry. Returns a boolean.

NETWORK DATABASES

These methods query the traditional Unix host, network, protocol, and service databases. Like the user/group lookups above, a successful result is returned as an Array of positional fields, and nil is returned when nothing is found.

gethostbyname

self.gethostbyname(name)

Looks up a host by name. Returns an array [name, aliases, addrtype, length, addrs], where aliases is a single (possibly space-separated) string of alternate names, and addrs is an array of address strings.

var host = Sys.gethostbyname('localhost')
say host[0]   # name
say host[4]   # array of addresses

gethostbyaddr

self.gethostbyaddr(addr, addrtype)

Looks up a host by network address. addrtype specifies the address family (typically 2 for AF_INET). Returns the same array shape as "gethostbyname".

var host = Sys.gethostbyaddr("127.0.0.1", 2)

gethostent

self.gethostent

Returns the next entry from the hosts database, in the same array shape as "gethostbyname", or nil when there are no more entries. Use "sethostent" to rewind.

sethostent

self.sethostent(stayopen)

Opens and rewinds the hosts database. If stayopen is true, the database connection is kept open for efficiency. Returns a boolean.

getnetbyname

self.getnetbyname(name)

Looks up a network by name. Returns an array [name, aliases, addrtype, net].

var net = Sys.getnetbyname('loopback')

getnetbyaddr

self.getnetbyaddr(addr, addrtype)

Looks up a network by address and address type. Returns the same array shape as "getnetbyname".

getnetent

self.getnetent

Returns the next entry from the networks database, in the same array shape as "getnetbyname", or nil when there are no more entries. Use "setnetent" to rewind.

setnetent

self.setnetent(stayopen)

Opens and rewinds the networks database. If stayopen is true, the database connection is kept open for efficiency. Returns a boolean.

getprotobyname

self.getprotobyname(name)

Looks up a protocol by name (e.g., 'tcp', 'udp', 'icmp'). Returns an array [name, aliases, proto].

var proto = Sys.getprotobyname('tcp')
say proto[2]  # protocol number, as a string

getprotobynumber

self.getprotobynumber(num)

Looks up a protocol by its number. Returns the same array shape as "getprotobyname".

var proto = Sys.getprotobynumber(6)  # TCP

getprotoent

self.getprotoent

Returns the next entry from the protocols database, in the same array shape as "getprotobyname", or nil when there are no more entries. Use "setprotoent" to rewind.

setprotoent

self.setprotoent(stayopen)

Opens and rewinds the protocols database. If stayopen is true, the database connection is kept open for efficiency. Returns a boolean.

getservbyname

self.getservbyname(name, proto)

Looks up a service by name and protocol. Returns an array [name, aliases, port, proto], where port is a number.

var service = Sys.getservbyname('http', 'tcp')
say service[2]  # 80

getservbyport

self.getservbyport(port, proto)

Looks up a service by port number and protocol. Returns the same array shape as "getservbyname".

var service = Sys.getservbyport(80, 'tcp')
say service[0]  # "http"

getservent

self.getservent

Returns the next entry from the services database, in the same array shape as "getservbyname", or nil when there are no more entries. Use "setservent" to rewind.

setservent

self.setservent(stayopen)

Opens and rewinds the services database. If stayopen is true, the database connection is kept open for efficiency. Returns a boolean.

EXAMPLES

Forking a Child Process

var pid = Sys.fork

if ((pid == 0)) {
    say "Child process running"
    Sys.exit(0)
}
else {
    Sys.wait
    say "Child has finished"
}

Reading Typed Input

var name  = Sys.scanln("Name: ")
var count = Sys.read("How many apples? ", Number)
Sys.printf("%s has %d apples\n", name, count)

Redirecting Output Temporarily

Sys.open(var fh, '>', 'log.txt')
var old = Sys.select(fh)
say "This line goes to log.txt"
Sys.select(old)
say "This line goes back to the terminal"
fh.close

Running a Command and Checking the Result

var status = Sys.system("grep", "-q", "root", "/etc/passwd")

if ((status == 0)) {
    say "Found it"
}
else {
    say "grep exited with code #{status >> 8}"
}

Looking Up a User

var pw = Sys.getpwnam('root')

if (pw) {
    say "UID: #{pw[2]}"
    say "Shell: #{pw[7]}"
}

SEE ALSO

Sidef::Object::Object