Class: Ukiryu::Shell::Tcsh
Overview
Tcsh (TENEX C Shell) implementation
Tcsh is a C shell variant with enhancements including command-line editing, history expansion, and programmable completion.
Key differences from bash/sh:
-
Uses C shell syntax (not POSIX sh compatible)
-
History expansion with ! (major difference)
-
Variable assignment: set var = value
-
Environment variables: setenv VAR value
-
Arrays: set arr = (a b c)
-
Special characters: ! ^ ~ # $ * ? [ ] { } | ; & < > ( )
Tcsh cannot inherit from UnixBase because it uses different syntax and doesn’t support the same -c flag execution method.
Constant Summary collapse
- SHELL_NAME =
:tcsh- PLATFORM =
:unix- EXECUTABLE =
'tcsh'
Constants inherited from Base
Base::SPECIAL_CHARS_PATTERN, Base::WHITESPACE_PATTERN
Class Method Summary collapse
-
.detect_alias(command_name) ⇒ Hash?
Detect if a command is a Tcsh alias.
Instance Method Summary collapse
-
#env_var(name) ⇒ String
Format an environment variable reference.
-
#escape(string) ⇒ String
Escape a string for Tcsh.
-
#execute_command(executable, args, env, timeout, cwd = nil) ⇒ Hash
Execute a command using Tcsh.
-
#execute_command_with_stdin(executable, args, env, timeout, cwd, stdin_data) ⇒ Hash
Execute a command with stdin input using Tcsh.
-
#format_path(path) ⇒ String
Format a file path for Tcsh Tcsh on Unix uses forward slashes.
-
#headless_environment ⇒ Hash
Tcsh doesn’t need DISPLAY variable.
-
#join(executable, *args) ⇒ String
Join executable and arguments into a command line.
- #name ⇒ Object
-
#quote(string) ⇒ String
Quote an argument for Tcsh.
Methods inherited from Base
#capabilities, #encoding, #environment_to_h, #format_environment, #needs_quoting?, #supports?
Class Method Details
.detect_alias(command_name) ⇒ Hash?
Detect if a command is a Tcsh alias
Tcsh uses the ‘alias’ builtin with its own format.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/ukiryu/shell/tcsh.rb', line 34 def self.detect_alias(command_name) # Tcsh's alias command returns: "alias ll ls -l" result = `tcsh -c "alias #{command_name}" 2>/dev/null` return nil unless result # Parse tcsh alias format # Format: "alias ll ls -l" or "ll: aliased to ls -l" if result =~ /^#{command_name}\s+(.+)$/ { definition: result.strip, target: ::Regexp.last_match(1).split(/\s+/).first } elsif result =~ /^#{command_name}:\s+aliased to\s+(.+)$/ { definition: result.strip, target: ::Regexp.last_match(1).split(/\s+/).first } end nil end |
Instance Method Details
#env_var(name) ⇒ String
Format an environment variable reference
97 98 99 |
# File 'lib/ukiryu/shell/tcsh.rb', line 97 def env_var(name) "$#{name}" end |
#escape(string) ⇒ String
Escape a string for Tcsh
Tcsh has complex escaping rules:
-
! must always be escaped (history expansion)
-
Other special chars: ^ ~ # $ * ? [ ] { } | ; & < > ( )
-
Backslash escapes the next character
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/ukiryu/shell/tcsh.rb', line 62 def escape(string) # Escape characters that have special meaning in tcsh # ! is the most important (history expansion) # $ is used for variables # ` for command substitution # " for quoting # \ for escaping # Other special chars that might need escaping in certain contexts string.to_s.gsub(/[!$`"\\]/) { "\\#{::Regexp.last_match(0)}" } end |
#execute_command(executable, args, env, timeout, cwd = nil) ⇒ Hash
Execute a command using Tcsh
Tcsh uses -c flag for command execution, similar to other shells.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/ukiryu/shell/tcsh.rb', line 137 def execute_command(executable, args, env, timeout, cwd = nil) require 'open3' require 'timeout' # Build command string using this shell's quoting rules command_string = join(executable, *args) # Find tcsh executable tcsh_path = Ukiryu::Executor.find_executable('tcsh') raise 'tcsh not found in system PATH' unless tcsh_path # Convert Environment to Hash ONLY at Open3 call site env_hash = environment_to_h(env) # Execute using tcsh's -c flag Timeout.timeout(timeout) do execution = lambda do stdout, stderr, status = Open3.capture3(env_hash, tcsh_path, '-c', command_string) { status: Ukiryu::Executor.extract_status(status), stdout: stdout, stderr: stderr } end if cwd Dir.chdir(cwd) { execution.call } else execution.call end end rescue Timeout::Error, Timeout::ExitException raise Timeout::Error, "Command timed out after #{timeout}s: #{executable}" end |
#execute_command_with_stdin(executable, args, env, timeout, cwd, stdin_data) ⇒ Hash
Execute a command with stdin input using Tcsh
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/ukiryu/shell/tcsh.rb', line 182 def execute_command_with_stdin(executable, args, env, timeout, cwd, stdin_data) require 'open3' require 'timeout' # Build command string using this shell's quoting rules command_string = join(executable, *args) # Find tcsh executable tcsh_path = Ukiryu::Executor.find_executable('tcsh') raise 'tcsh not found in system PATH' unless tcsh_path # Convert Environment to Hash ONLY at Open3 call site env_hash = environment_to_h(env) # Execute using tcsh's -c flag Timeout.timeout(timeout) do execution = lambda do Open3.popen3(env_hash, tcsh_path, '-c', command_string) do |stdin, stdout, stderr, wait_thr| # Write stdin data begin if stdin_data.is_a?(IO) IO.copy_stream(stdin_data, stdin) elsif stdin_data.is_a?(String) stdin.write(stdin_data) end rescue Errno::EPIPE # Process closed stdin early (e.g., 'head' command) ensure stdin.close end # Read output out = stdout.read err = stderr.read # Wait for process to complete status = wait_thr.value { status: Ukiryu::Executor.extract_status(status), stdout: out, stderr: err } end end if cwd Dir.chdir(cwd) { execution.call } else execution.call end end rescue Timeout::Error, Timeout::ExitException raise Timeout::Error, "Command timed out after #{timeout}s: #{executable}" end |
#format_path(path) ⇒ String
Format a file path for Tcsh Tcsh on Unix uses forward slashes
115 116 117 |
# File 'lib/ukiryu/shell/tcsh.rb', line 115 def format_path(path) path end |
#headless_environment ⇒ Hash
Tcsh doesn’t need DISPLAY variable
122 123 124 |
# File 'lib/ukiryu/shell/tcsh.rb', line 122 def headless_environment {} end |
#join(executable, *args) ⇒ String
Join executable and arguments into a command line
106 107 108 |
# File 'lib/ukiryu/shell/tcsh.rb', line 106 def join(executable, *args) [quote(executable), *args.map { |a| quote(a) }].join(' ') end |
#name ⇒ Object
49 50 51 |
# File 'lib/ukiryu/shell/tcsh.rb', line 49 def name :tcsh end |
#quote(string) ⇒ String
Quote an argument for Tcsh
Tcsh supports both single and double quotes. Single quotes are literal (except for ‘ which ends the quote). Double quotes allow variable expansion and command substitution.
However, ! (history expansion) can still occur even in quotes! The safest approach is to escape ! with backslash first.
84 85 86 87 88 89 90 91 |
# File 'lib/ukiryu/shell/tcsh.rb', line 84 def quote(string) # For tcsh, we need to: # 1. Escape ! characters (history expansion) # 2. Escape ' characters if present # 3. Wrap in single quotes escaped = string.to_s.gsub(/!/) { '\\!' }.gsub("'") { "'\\''" } "'#{escaped}'" end |