๐Ÿ’ป Online Terminal Emulator

Practice CLI commands in your browser โ† All Tools
guest@lifa-tools: ~
guest@lifa ~ $

๐Ÿ“‹ Available Commands

help list commands
ls list files
ls -la detailed list
pwd current dir
cd change dir
cat read file
mkdir create dir
touch create file
echo print text
whoami current user
date current date
uname system info
history cmd history
clear clear screen
rm remove file
cp copy file
\n'},'style.css':{type:'file',content:'body { margin: 0; font-family: sans-serif; }'},'app.js':{type:'file',content:'console.log("App started");\n\nfunction init() {\n return fetch("/api/data");\n}'}}},'api-server':{type:'dir',children:{'server.js':{type:'file',content:'const express = require("express");\nconst app = express();\napp.listen(3000);'},'package.json':{type:'file',content:'{\n "name": "api-server",\n "version": "1.0.0",\n "main": "server.js"\n}'}}}}},'readme.md':{type:'file',content:'# Welcome to Lifa Terminal\n\nThis is a simulated terminal environment.\nTry running some commands!\n\n## Quick Start\n- Type `help` to see available commands\n- Use `ls` to list files\n- Use `cd` to navigate directories'},'notes.txt':{type:'file',content:'TODO:\n- Finish the API\n- Write tests\n- Deploy to production'},'.bashrc':{type:'file',content:'# ~/.bashrc\nexport PATH=$PATH:/usr/local/bin\nalias ll="ls -la"\nalias gs="git status"'},'.gitconfig':{type:'file',content:'[user]\n name = guest\n email = [email protected]'}}} }; function resolvePath(p){ if(p.startsWith('/')) return p; if(p.startsWith('~')) return '/home/guest'+p.slice(1); let parts=cwd.split('/').filter(Boolean); p.split('/').forEach(s=>{ if(s==='..') parts.pop(); else if(s!=='.') parts.push(s); }); return '/'+parts.join('/'); } function getNode(path){ if(path==='/home/guest') return fs['/home/guest']; const rel=path.replace('/home/guest/','').replace('/home/guest',''); if(!rel) return fs['/home/guest']; let node=fs['/home/guest']; const parts=rel.split('/').filter(Boolean); for(const p of parts){ if(!node||node.type!=='dir'||!node.children[p]) return null; node=node.children[p]; } return node; } function getParentAndName(path){ const parts=path.split('/').filter(Boolean); const name=parts.pop(); const parentPath='/'+parts.join('/'); return{parent:getNode(parentPath)||getNode('/home/guest'),name,parentPath}; } function shortCwd(){ return cwd.replace('/home/guest','~')||'~'; } function updatePrompt(){ promptEl.textContent=`guest@lifa ${shortCwd()} $`; } function addLine(text,cls='output'){ const div=document.createElement('div'); div.className='line '+cls; div.textContent=text; output.appendChild(div); } function addHTML(html,cls='output'){ const div=document.createElement('div'); div.className='line '+cls; div.innerHTML=html; output.appendChild(div); } const commands={ help(){ addLine('Available commands:','info'); const cmds=[ ['help','Show this help message'],['ls [-la]','List directory contents'],['cd ','Change directory'], ['pwd','Print working directory'],['cat ','Display file contents'],['echo ','Print text'], ['mkdir ','Create directory'],['touch ','Create empty file'],['rm ','Remove file/directory'], ['cp ','Copy file'],['mv ','Move/rename file'],['whoami','Display current user'], ['date','Display current date/time'],['uname [-a]','System information'],['history','Command history'], ['clear','Clear terminal'],['tree','Show directory tree'],['wc ','Word/line count'], ['head ','First 5 lines'],['grep ','Search in file'],['env','Environment variables'] ]; cmds.forEach(([c,d])=>addLine(` ${c.padEnd(22)} ${d}`)); }, ls(args){ const showAll=args.includes('-a')||args.includes('-la')||args.includes('-al'); const showLong=args.includes('-l')||args.includes('-la')||args.includes('-al'); const target=args.filter(a=>!a.startsWith('-'))[0]; const path=target?resolvePath(target):cwd; const node=getNode(path); if(!node||node.type!=='dir'){addLine(`ls: cannot access '${target}': No such file or directory`,'error');return;} let entries=Object.keys(node.children); if(showAll) entries=['.','..', ...entries]; else entries=entries.filter(e=>!e.startsWith('.')); if(showLong){ entries.forEach(e=>{ if(e==='.'||e==='..'){addLine(`drwxr-xr-x guest guest 4096 ${e}`);return;} const n=node.children[e]; const perm=n.type==='dir'?'drwxr-xr-x':'-rw-r--r--'; const size=n.type==='dir'?'4096':String(n.content?.length||0).padStart(4); addLine(`${perm} guest guest ${size} ${e}`); }); } else { addLine(entries.map(e=>{ const n=node.children[e]; return(n&&n.type==='dir')?e+'/':e; }).join(' ')); } }, cd(args){ const target=args[0]||'~'; const path=resolvePath(target); const node=getNode(path); if(!node||node.type!=='dir'){addLine(`cd: no such directory: ${target}`,'error');return;} cwd=path; updatePrompt(); }, pwd(){addLine(cwd);}, cat(args){ if(!args[0]){addLine('cat: missing operand','error');return;} const path=resolvePath(args[0]); const node=getNode(path); if(!node){addLine(`cat: ${args[0]}: No such file or directory`,'error');return;} if(node.type==='dir'){addLine(`cat: ${args[0]}: Is a directory`,'error');return;} addLine(node.content||''); }, echo(args){addLine(args.join(' '));}, mkdir(args){ if(!args[0]){addLine('mkdir: missing operand','error');return;} const path=resolvePath(args[0]); const{parent,name}=getParentAndName(path); if(!parent){addLine(`mkdir: cannot create directory '${args[0]}'`,'error');return;} if(parent.children[name]){addLine(`mkdir: cannot create directory '${name}': File exists`,'error');return;} parent.children[name]={type:'dir',children:{}}; addLine(`Directory '${name}' created`,'info'); }, touch(args){ if(!args[0]){addLine('touch: missing operand','error');return;} const path=resolvePath(args[0]); const{parent,name}=getParentAndName(path); if(!parent){addLine(`touch: cannot touch '${args[0]}'`,'error');return;} if(!parent.children[name]) parent.children[name]={type:'file',content:''}; }, rm(args){ const force=args.includes('-rf')||args.includes('-r'); const target=args.filter(a=>!a.startsWith('-'))[0]; if(!target){addLine('rm: missing operand','error');return;} const path=resolvePath(target); const{parent,name}=getParentAndName(path); const node=parent?.children[name]; if(!node){addLine(`rm: cannot remove '${target}': No such file or directory`,'error');return;} if(node.type==='dir'&&!force){addLine(`rm: cannot remove '${target}': Is a directory (use -rf)`,'error');return;} delete parent.children[name]; addLine(`Removed '${name}'`,'info'); }, cp(args){ if(args.length<2){addLine('cp: missing operand','error');return;} const srcPath=resolvePath(args[0]); const srcNode=getNode(srcPath); if(!srcNode||srcNode.type==='dir'){addLine(`cp: cannot copy '${args[0]}'`,'error');return;} const dstPath=resolvePath(args[1]); const{parent,name}=getParentAndName(dstPath); if(!parent){addLine(`cp: cannot copy to '${args[1]}'`,'error');return;} parent.children[name]={type:'file',content:srcNode.content}; addLine(`Copied '${args[0]}' โ†’ '${args[1]}'`,'info'); }, mv(args){ if(args.length<2){addLine('mv: missing operand','error');return;} const srcPath=resolvePath(args[0]); const{parent:srcParent,name:srcName}=getParentAndName(srcPath); const srcNode=srcParent?.children[srcName]; if(!srcNode){addLine(`mv: cannot move '${args[0]}': No such file`,'error');return;} const dstPath=resolvePath(args[1]); const{parent:dstParent,name:dstName}=getParentAndName(dstPath); if(!dstParent){addLine(`mv: cannot move to '${args[1]}'`,'error');return;} dstParent.children[dstName]=srcNode; delete srcParent.children[srcName]; addLine(`Moved '${args[0]}' โ†’ '${args[1]}'`,'info'); }, whoami(){addLine('guest');}, date(){addLine(new Date().toString());}, uname(args){ if(args.includes('-a')) addLine('Linux lifa-tools 5.15.0-generic #1 SMP x86_64 GNU/Linux'); else addLine('Linux'); }, history(){history.forEach((c,i)=>addLine(` ${String(i+1).padStart(4)} ${c}`));}, clear(){output.innerHTML='';}, tree(args){ const path=args[0]?resolvePath(args[0]):cwd; const node=getNode(path); if(!node||node.type!=='dir'){addLine(`tree: '${args[0]||'.'}' is not a directory`,'error');return;} addLine(path===cwd?'.':args[0]); let count={dirs:0,files:0}; function walk(n,prefix){ const keys=Object.keys(n.children).filter(k=>!k.startsWith('.')); keys.forEach((k,i)=>{ const last=i===keys.length-1; const connector=last?'โ””โ”€โ”€ ':'โ”œโ”€โ”€ '; const child=n.children[k]; addLine(prefix+connector+k+(child.type==='dir'?'/':'')); if(child.type==='dir'){count.dirs++;walk(child,prefix+(last?' ':'โ”‚ '));} else count.files++; }); } walk(node,''); addLine(`\n${count.dirs} directories, ${count.files} files`,'info'); }, wc(args){ if(!args[0]){addLine('wc: missing operand','error');return;} const path=resolvePath(args[0]); const node=getNode(path); if(!node||node.type==='dir'){addLine(`wc: ${args[0]}: No such file`,'error');return;} const lines=(node.content||'').split('\n').length; const words=(node.content||'').split(/\s+/).filter(Boolean).length; const chars=(node.content||'').length; addLine(` ${lines} ${words} ${chars} ${args[0]}`); }, head(args){ if(!args[0]){addLine('head: missing operand','error');return;} const path=resolvePath(args[0]); const node=getNode(path); if(!node||node.type==='dir'){addLine(`head: ${args[0]}: No such file`,'error');return;} (node.content||'').split('\n').slice(0,5).forEach(l=>addLine(l)); }, grep(args){ if(args.length<2){addLine('grep: missing operand','error');return;} const pattern=args[0]; const path=resolvePath(args[1]); const node=getNode(path); if(!node||node.type==='dir'){addLine(`grep: ${args[1]}: No such file`,'error');return;} const lines=(node.content||'').split('\n'); let found=false; lines.forEach(l=>{if(l.toLowerCase().includes(pattern.toLowerCase())){addLine(l);found=true;}}); if(!found) addLine(`(no matches for '${pattern}')`,'info'); }, env(){ const vars=['USER=guest','HOME=/home/guest','SHELL=/bin/bash','PATH=/usr/local/bin:/usr/bin:/bin','LANG=en_US.UTF-8','TERM=xterm-256color','EDITOR=vim','NODE_VERSION=20.11.0','NPM_VERSION=10.2.4']; vars.forEach(v=>addLine(v)); } }; function execCmd(raw){ const trimmed=raw.trim(); if(!trimmed) return; history.push(trimmed); histIdx=history.length; addLine(`${shortCwd()} $ ${trimmed}`,'cmd'); const parts=trimmed.split(/\s+/); const cmd=parts[0]; const args=parts.slice(1); if(commands[cmd]) commands[cmd](args); else addLine(`${cmd}: command not found. Type 'help' for available commands.`,'error'); output.scrollTop=output.scrollHeight; } function runCmd(cmd){ input.value=cmd; execCmd(cmd); input.value=''; input.focus(); } input.addEventListener('keydown',e=>{ if(e.key==='Enter'){execCmd(input.value);input.value='';} else if(e.key==='ArrowUp'){e.preventDefault();if(histIdx>0){histIdx--;input.value=history[histIdx];}} else if(e.key==='ArrowDown'){e.preventDefault();if(histIdxk.startsWith(partial)); if(matches.length===1){parts[parts.length-1]=matches[0];input.value=parts.join(' ');} else if(matches.length>1) addLine(matches.join(' '),'info'); } } else if(e.key==='l'&&e.ctrlKey){e.preventDefault();commands.clear();} }); function clearTerminal(){commands.clear();input.focus();} document.addEventListener('click',e=>{if(!e.target.closest('.cmd-tag')&&!e.target.closest('button'))input.focus();}); // Welcome message addLine('Welcome to Lifa Online Terminal v1.0.0','info'); addLine('Type "help" to see available commands.\n','info'); updatePrompt();