NAME
Sidef::Types::Glob::Backtick - Shell command execution via backticks
SYNOPSIS
# Execute a shell command and capture its output
var out = `ls -1`
say out
# With string interpolation
var dir = "/tmp"
var files = `ls #{dir}`
# Explicit object usage (normally implicit)
var cmd = Backtick("uname -a")
var out = cmd.call
say out
# Chaining with string methods
var user = `whoami`.trim
var lines = `cat file.txt`.lines
# Using in expressions
if (`which git`.trim) {
say "Git is installed"
}
DESCRIPTION
The Sidef::Types::Glob::Backtick class represents a backtick expression in Sidef, which executes shell commands and captures their output.
A backtick expression executes a command using the system shell (typically /bin/sh on Unix-like systems or cmd.exe on Windows) and returns the command's standard output as a String object.
This behavior is analogous to backticks in Perl, Ruby, or POSIX shells:
`command`
The command is executed in a subshell with the output captured and returned as a string. All text written to STDOUT is captured, while STDERR is not captured by default (it goes to the parent process's STDERR).
Common Use Cases
Backtick expressions are typically used for:
Querying system information (kernel version, hostname, etc.)
Interfacing with external command-line programs
Capturing output from Unix utilities in scripts
Quick system administration tasks
Reading data from external sources via shell commands
INHERITS
This class inherits from:
METHODS
call
var output = backtick_obj.call
var output = backtick_obj()
Executes the stored shell command and returns its standard output as a String.
The returned string includes everything written to STDOUT by the command, including any trailing newlines. Trailing whitespace is not automatically removed; use the trim method if needed.
Return value: String containing the command's output
Exit status: The exit status of the command is not returned. If you need to check the exit status, use the Sys.run method instead.
Error handling: If the command fails or cannot be found, behavior depends on the shell. Typically:
An empty string may be returned
Partial output up to the point of failure may be returned
Shell error messages may appear on STDERR
Example:
var kernel = Backtick("uname -r")
say kernel.call
run
var output = backtick_obj.run
Alias for call. Executes the command and returns its output.
This method exists for internal consistency with other callable Sidef objects and for compatibility with the general "run" interface pattern.
Example:
var cmd = Backtick("date")
var timestamp = cmd.run
to_s
var command_string = backtick_obj.to_s
Returns the literal command string represented by the backtick expression without executing it.
This is useful for:
Debugging - see what command would be executed
Logging - record the command before execution
Introspection - examining backtick objects programmatically
Return value: String containing the command text
Example:
var cmd = Backtick("ls -la")
say cmd.to_s # prints: ls -la
say cmd.call # executes and returns output
dump
var representation = backtick_obj.dump
Returns a string representation of the Backtick object suitable for debugging.
Example:
var cmd = Backtick("echo hello")
say cmd.dump # Backtick("echo hello")
BACKTICK SYNTAX
Backticks can be written directly in Sidef source code using the grave accent character (`` ` ``):
var date = `date`
var user = `whoami`
var files = `ls *.sidef`
The command string is passed to the system shell exactly as written, allowing full use of shell features.
String Interpolation
Backtick expressions support Sidef string interpolation, allowing variables to be embedded in commands:
var dir = "/home/user"
var count = `ls #{dir} | wc -l`
var filename = "data.txt"
var contents = `cat #{filename}`
Shell Features
Since commands are executed by the shell, all shell features are available:
Pipes:
`ps aux | grep firefox`Redirections:
`command 2&1`>Glob expansion:
`ls *.txt`Command substitution:
`echo $(date)`Environment variables:
`echo $HOME`Logical operators:
`command1 && command2`
Example with shell features:
# Multiple commands
var info = `uname -s && uname -r`
# Pipe through multiple commands
var top_processes = `ps aux | sort -rn -k 3 | head -5`
# Redirection
var combined = `command 2>&1`
EXAMPLES
Basic Command Execution
# Get current date
var date = `date`
say date
# Get username
var user = `whoami`.trim
say "Hello, #{user}!"
# Check if command exists
var git_path = `which git 2>/dev/null`.trim
if (git_path) {
say "Git found at: #{git_path}"
}
Using Shell Pipelines
# Count running processes
var count = `ps aux | wc -l`.to_i
say "Running processes: #{count}"
# Find large files
var large = `find . -type f -size +1M | head -10`
say large
# Text processing
var words = `cat file.txt | tr ' ' '\n' | sort | uniq -c`
String Processing
# Trim whitespace
var hostname = `hostname`.trim
say hostname
# Split output into lines
var files = `ls`.lines
files.each { |file|
say "File: #{file}"
}
# Parse structured output
var df = `df -h`.lines
df.each { |line|
var parts = line.split(/\s+/)
say parts
}
Conditional Execution
# Check if program is installed
if (`which python3`.trim) {
say "Python 3 is installed"
var version = `python3 --version`.trim
say version
}
# Check command success by output
var status = `systemctl is-active nginx 2>/dev/null`.trim
if (status == "active") {
say "Nginx is running"
}
Capturing and Processing Output
# Get and parse date components
var date_parts = `date +%Y-%m-%d`.trim.split('-')
var (year, month, day) = date_parts...
say "Year: #{year}, Month: #{month}, Day: #{day}"
# Read file through command
var lines = `cat /etc/hosts`.lines.grep { !_.starts_with('#') }
lines.each { |line| say line }
# Process JSON output from command
# var json = `curl -s api.example.com/data`.trim
# var data = json.parse_json
Working with Files
# List files modified today
var today_files = `find . -type f -mtime 0`
say today_files
# Count lines in source files
var line_count = `find . -name '*.sidef' -exec wc -l {} + | tail -1`.trim
say "Total lines: #{line_count}"
# Search for pattern
var matches = `grep -r "TODO" . 2>/dev/null`
if (matches) {
say "Found TODOs:"
say matches
}
System Information
# Get system information
var os = `uname -s`.trim
var kernel = `uname -r`.trim
var arch = `uname -m`.trim
say "OS: #{os}"
say "Kernel: #{kernel}"
say "Architecture: #{arch}"
# Get memory info (Linux)
var mem = `free -h | grep Mem`.trim
say mem
# Get disk usage
var disk = `df -h /`.lines[1]
say "Root disk: #{disk}"
Advanced Usage
# Combine with error handling
var output = ""
try {
output = `command 2>&1`.trim
} catch {
say "Command failed"
}
# Use in array/hash construction
var env = Hash(
user: `whoami`.trim,
home: `echo $HOME`.trim,
shell: `echo $SHELL`.trim
)
say env
# Filter and transform
var users = `cut -d: -f1 /etc/passwd`.lines.sort
say "System users: #{users.join(', ')}"
SECURITY CONSIDERATIONS
Backtick expressions execute arbitrary shell commands with the privileges of the running process. Extreme caution is required when using user input.
Command Injection Vulnerability
Never interpolate untrusted input into backtick expressions without proper validation or escaping. This can lead to command injection vulnerabilities where attackers can execute arbitrary commands.
Unsafe example (VULNERABLE):
# DANGEROUS - DO NOT USE
var filename = readln # User input
var content = `cat #{filename}` # EXPLOITABLE!
# If user enters: file.txt; rm -rf /
# The command becomes: cat file.txt; rm -rf /
Safer alternatives:
- 1. Validate input against a whitelist of allowed values
-
var filename = readln.trim if (filename ~~ /^[a-zA-Z0-9._-]+$/) { var content = `cat #{filename}` } else { die "Invalid filename" } - 2. Use File I/O instead of shell commands when possible
-
var filename = readln.trim var content = File(filename).read # Safer - no shell involved - 3. Use Sys.run with array arguments for proper escaping
-
var filename = readln.trim var content = Sys.run("cat", filename) - 4. Escape shell metacharacters (complex and error-prone)
-
# Not recommended - easy to get wrong var escaped = filename.escape var content = `cat #{escaped}`
Other Security Concerns
Environment variables - The shell environment is inherited and can affect command behavior
PATH injection - Ensure PATH is controlled in security-sensitive contexts
Working directory - Commands execute in the current directory
Shell features - Wildcards, pipes, and redirections can have unexpected effects
Best Practices
Only use backticks with trusted, static commands when possible
Prefer File I/O and Sidef built-ins over shell commands
Use
Sys.runorSys.execwith array arguments for better controlValidate and sanitize all user input before using in commands
Use absolute paths for commands in security-sensitive code
Consider using restricted shells or sandboxing for untrusted commands
RETURN VALUES AND ERROR HANDLING
Backtick expressions return the captured STDOUT as a String. Error handling is limited:
Exit status is not returned or checked
STDERR is not captured (goes to parent's STDERR)
Failed commands may return empty strings or partial output
Command not found errors depend on the shell
If you need more control over command execution:
# For exit status
var (output, status) = Sys.run("command")
if (status == 0) {
say "Success: #{output}"
}
# For STDERR capture
var output = `command 2>&1` # Redirect STDERR to STDOUT
# For complex execution control
Sys.exec("command", "arg1", "arg2")
PLATFORM DIFFERENCES
Command execution behavior varies by platform:
Unix/Linux/macOS: Uses
/bin/shor$SHELLWindows: Uses
cmd.exeorPowerShelldepending on configurationCommand syntax: Must match the target shell's syntax
Path separators: Unix uses
/, Windows uses\Available commands: Vary significantly between platforms
For portable code, either:
Use platform detection and conditional commands
Stick to commands available on all target platforms
Use Sidef built-ins instead of shell commands where possible
PERFORMANCE CONSIDERATIONS
Backtick expressions spawn a new shell process for each execution, which has overhead:
Process creation takes time (milliseconds)
Each execution creates a new shell + subprocess
Repeated execution in loops can be slow
For better performance:
# Slow - spawns 1000 shells
1000.times {
var date = `date`
}
# Better - call once, reuse result
var date = `date`
1000.times {
say date
}
# Best - use Sidef built-ins when available
var date = Time.now
1000.times {
say date
}
COMPARISON WITH OTHER APPROACHES
Backticks vs File I/O
# Using backticks
var content = `cat file.txt`
# Using File I/O (preferred)
var content = File("file.txt").read
File I/O is generally preferred because it's:
Faster (no shell overhead)
More portable (no external commands)
Safer (no command injection risk)
More predictable error handling
Backticks vs Sys Methods
# Backticks - simple, returns output only
var output = `command arg`
# Sys.run - returns output and exit status
var (output, status) = Sys.run("command", "arg")
# Sys.exec - replaces current process
Sys.exec("command", "arg")
Use Sys methods when you need:
Exit status checking
Better error handling
Argument array passing (safer with user input)
More control over execution environment
IMPLEMENTATION NOTES
Backtick expressions are represented in the Sidef AST using Sidef::Types::Glob::Backtick objects, which store the command string and execute it when evaluated.
Implementation details:
Command execution is delegated to the host operating system shell
Output capture uses standard process I/O redirection
The command string is evaluated at runtime, allowing interpolation
No caching - each
callexecutes the command again
DIAGNOSTICS
Common issues and solutions:
"Command not found" - Command is not in PATH or doesn't exist
Empty output - Command failed, has no output, or wrong redirect
Unexpected results - Shell interpretation of special characters
Permission denied - Insufficient permissions to execute command
Debugging tips:
# See the actual command
var cmd = Backtick("ls -la")
say cmd.to_s
# Capture errors
var output = `command 2>&1`
# Test command in shell first
# $ command arg1 arg2
SEE ALSO
Sidef::Types::String - String manipulation methods
Sidef::Types::Glob - Glob pattern matching
Sidef::Sys::Sys - System interface methods (
run,exec)Sidef::Types::Glob::File - File I/O operations
Perl
qx//operator (similar functionality)Ruby backticks (similar functionality)
POSIX shell command substitution
$(...)
AUTHOR
Daniel "trizen" Șuteu
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Sidef itself.