Unix (/ˈjuːnɪks/; trademarked as UNIX) is a family of multitasking, multiuser computer operating systems that derive from the original AT&T Unix
References
-
[unix-programming-enviornment] The UNIX Programming Enviornment by Brian W. Kernigan, Rob Pike
-
[POSIX-2017] POSIX.1-2017
-
[gnu-packages] GNU Manuals Online
-
[coreutils] GNU Coreutils 9.3
-
[findutils] GNU Findutils 4.9.0
Disclaimer
The document started as a notes of a Shell Programming course at UCT, Prague.
Terminology
- Linux kernel
-
The Linux kernel is a free and open-source, operating system kernel. It was originally authored in 1991 by Linus Torvalds. "The kernel is a computer program at the core of a computer’s operating system and generally has complete control over everything in the system, facilitates interactions between hardware and software components." — https://en.wikipedia.org/wiki/Kernel_(operating_system)
- GNU/Linux Operating System
-
"By 1990 we had either found or written all the major components except one—the kernel. Then Linux, a Unix-like kernel, was developed by Linus Torvalds in 1991 and made free software in 1992. Combining Linux with the almost-complete GNU system resulted in a complete operating system: the GNU/Linux system." — https://www.gnu.org/gnu/gnu-history.html
- Desktop Environment
-
Is an implementation of a bundle of programs running on top of a computer operating system that share a common graphical user interface (GUI). A desktop environment typically consists of icons, windows, toolbars, folders, wallpapers and desktop widgets. E.g. GNOME, KDE Plasma, XFCE.
- Linux Distribution
-
A Linux distribution (often abbreviated as distro) is an operating system made from a software collection. A typical Linux distribution comprises a Linux kernel, package management system, GNU tools and libraries, additional software, documentation, a window system (the most common being the X Window System, or, more recently, Wayland), a window manager, and a desktop environment. E.g. Debian, Ubuntu, Mint, Fedora, Gentoo.
- Package manager
-
"A package manager or package-management system is a collection of software tools that automates the process of installing, upgrading, configuring, and removing computer programs for a computer in a consistent manner." — https://en.wikipedia.org/wiki/Package_manager E.g. APT, pacman, yum.
- Terminal, command-line interface (CLI)
-
An application where you interact by typing commands at the bottom (the window). E.g. xterm, GNOME terminal, putty.
- Command-line
-
Is the line in the terminal, where you write commands.
- Shell (command-line interpreter)
-
The program which interprets what you type in the command-line. E.g. Bourne shell (sh), bash, zsh, dash.
- Prompt
-
First letters of the command-line that are static (does not change by typing).
What is POSIX?
is a family of standards specified by the IEEE Computer Society for maintaining compatibility between operating systems.[1] POSIX defines both the system and user-level application programming interfaces (APIs), along with command line shells and utility interfaces
Introduction
The terminal enviroment
Once the terminal is open, what you see is the Command-line interface (CLI). On the left to the cursor is the prompt, which prompts you to take action.
Usually the prompts tells a name of a current user, the name of the machine (hostname) and the location where the user is relatively to the machine (path). Typicaly it also shows, whether the logged user is a normal user ($) or superuser (#).
Example of common appearance could be:
USER_NAME@HOSTNAME:PATH$
Shell principle - commands and keywords
Shell is a scripting language, so you can do basically anything as in any other programming language. However shell is also a command language so most of the time you will run commands that someone already made for you. Once you will be able to use these commands, you will probably combine them into shell scripts.
What happens when I type something to the terminal
Many words have special meaning. Some words are reserved for the shell programming language, they are called keywords, multiple words are built-in commands and usually there are also many executable commands prepared for you.
Comments - tell shell to ignore it
Everything between a hash sign #
and the end of the line is ignored. So it is perfect for making comments or remarks.
# anything written here is ignored
Sometimes I will use the #
sign to show you the command’s output. It is ignored, so it does not matter if you copy-past the lines with it or not.
Motivation to use the terminal
find . -type f | grep -v '/\.' | wc -l
Note
|
You can read it from the back as "Count how many (wc -l ) visible (grep -v '/\.' ) files are under this directory (find . -type f )".
|
Text | Explanation |
---|---|
|
Command find, searches for files and directories. |
|
|
|
find’s argument to search only files. |
|
Pipe, passes command’s output as an input to the next command. |
|
Command grep, filters out lines which don’t match given pattern. |
|
grep’s argument to filter the matching lines and keep others. |
|
Pattern for a "hidden" file or directory (begins with a dot). |
|
Pipe again. |
|
Command to count lines, words and bytes. |
|
wc’s argument to output only the number of lines. |
command exit
exit
command terminates current shell. If you run only one shell, it also close the terminal. Shell is case-sensitive, so while exit
followed by enter closes the terminal, Exit
only tells you that Exit: command not found
.
Exit
# Exit: command not found
command echo
Let’s start with printing "Hello world!". Type echo Hello world!
and press enter.
echo Hello world! # Hello world!
Command Arguments and Options
You can pass arguments to the commands such you passed Hello world!
to echo
command. Commonly, the commands also have multiple options to be run with.
Probably the most common option is the option --help
or -h
that should help you with the command usage.
exit --help
# exit: exit [n]
# Exit the shell.
#
# Exits the shell with a status of N. If N is omitted, the exit status
# is that of the last command executed.
It is common there are two types of options.
-
Single letter, starts with hyphen-minus character
-x
-
full text (no spaces), stars with double minus
--xxxx
So the command structure look like this command [-o | --options] [arguments]
.
USE TAB AUTOCOMPLETION
Whenever, you press tab, the terminal autocomplete the word you are writing. If there is more than one posibility, nothing happens. Until you press tab twice. Than it shows you the all the possible completions.
It’s unbelievable great feature.
USE SHELL HISTORY
It is a huge mistake to write commands more than once. Shell remembers what commands you have written, so you can just call them from the history. In case you used it as the previous command, press [arrow up]
. In case you wrote it some commands ago, press [ctrl-r]
and start typing, if the result is not what you want, you either press [ctrl-r]
again for next match, or [ecs]
to end the search.
Command Types
There are several command types:
Type | Description |
---|---|
unknown |
|
builtin |
use |
executable |
files in |
functions |
defined functions (by user) |
aliases |
concatenating more commands |
command type
Let’s check the type of the echo
command.
type echo # echo is a shell builtin
Ok, echo
is a built-in command. Can i find where it is?
# type command with option -a
type -a echo
# echo is a shell builtin
# echo is /bin/echo
command enable, command compgen, command function, command alias, command unalias
# To enable or disable shell builtins
enable
# List builtins
compgen -b
# Define function
function greet() { echo "hello"; }
# Create alias
alias my_alias='command_1; command_2'
# Destory alias
unalias
More information about commands
command help, command info, command man, command apropos
Show appropriate manual pages for given TERM
man -k TERM # Equivalent to command "apropos TERM"
Expansions and suppressions
Not everything you write to shell is interpreted as you wrote it. Some characters are suppressed and others are expanded.
White space characters are suppressed.
echo The triple spaces are shrinken .
# The triple spaces are shrinken .
Some character such as tilda ~
are expanded.
echo ~
# /home/YOUR_USERNAME
There are various expansions for now it is good to know this:
"double quotes" - prevents all suppressions and expansions except $ notations.
echo "~ $USER ."
# ~ YOUR_USERNAME .
'single quotes' - takes it as it is.
echo '~ $USER .'
# ~ $USER .
Files and directories
Paths
There is always a need to specify a path to the file a directory you want to work with. The file can be a document you want to read, an image or simply anything. Directory is a container for such a files and other directories. Besides the files and directories the path may specify a command to be used.
There is already a directory structure by default. Important is that there is one root directory, where every other directories are either in the root directory or nested into its subdirectories. Also every user has its own user directory. At every point in a terminal you are in some directory.
Symbol | Path |
---|---|
|
The root directory. |
|
|
|
Your home directory, usually |
|
Your current directory. |
|
Directory one above your current directory. |
# Show path to the current directory
pwd # /home/USER/Desktop/DIR
# Show full path to directory or file.
realpath / # /
realpath ~ # /home/USER
realpath . # /home/USER/Desktop/DIR
realpath .. # /home/User/Desktop
Change current Directory (cd
)
cd /home/username/path/to/the/directory
cd # Plain cd moves to the home directory i.e. works same as cd ~
cd - # Goes to the direcotry you was previously in.
Manipulation with files and directories
# Create new directory
mkdir NEW_DIRECTORY
mkdir -p ./path/to/end/dir # create every dir that does not exist on the path
# Copy files and directories
cp file1 file2 # Copy file1 to file2
cp -r dir1 dir2 # Copy all from dir1 to dir2
# Move file to another place
mv /old/path/to/file1 /new/path/to/file1
# Rename file1 as file2 and check if not overwriting
mv -i file1 file2
# Create new directory and put everything in
mv ./!(dir1) ./dir1/
# Rename directories tutorial_01,tutorial_02,tutorial_03 to t_01, t_02, t_03
for var in 0{1,2,3}; do mv tutorial_$var t_$var; done
# Replace space with underscore
for file in *; do mv "$file" `echo $file | tr ' ' '_'` ; done
# Add word before extension (file_whatever.png -> file_whatever_historical.png)
for file in *; do mv "$file" $(echo ${file%%.*}_historical.png); done
# Delete files and directories
rm file # Remove file
rm -r # Remove directory (recursively with all files)
Information about files, directories
Commands: ls, tree, du, wc, stat
# Shows all files of given directory
ls ./path/to/the/directory
# Show structure of all files and dictionaries from your dictionary
tree
# Shows counts of lines, words and bytes
wc FILE_NAME
# show number of lines (-l) words (-w) and bytes (-c)
wc -l FILE_NAME
# Recursively shows sizes (disk usage) of directories and files
du ./path/to/the/directory
# Show size of the DIRECTORY and its direct children (2 ~ levels down etc.)
du -d 1 ./path/to/the/DIRECTORY
# Display info in human readable form (-h) only for the top folder (-s)
du -hs FILE_NAME
# Display all file and directory sizes
du -a
# show file statistics
stat file1
Compression and decompression
(Uploading and downloading in ohter way is damn slow)
Command zip
Zip files into new.zip
zip new file1 file2 file3
Unzip files from new.zip
unzip new.zip
# to NEW_DIR
unzip new.zip -d PATH/NEW_DIR
Command tar
Compress files to new.tar.gz
# -c = create
# -v = verbose
# -z = gzip / gz / zip
# -f = following files
tar -cvzf new.tar.gz file1 file2 file3
Decompress from new.tar.gz
# -x = extract
tar -xvzf oldFile.tar.gz
Decompress from new.tar.bz2
# -j = bz2
# -C = where to extract
tar -xvjf oldFile.tar.bz2 -C /path/Directory
Links
soft link
Points to the original file, can be used as the original file for multiple purposes.
# Ways to create soft links
ln -s FILENAME LINKNAME
cp -s FILENAME LINKNAME
Example Usage
* I installed "code_like_hell" editor with the executable file at /usr/share/code_like_hell/bin/code_like_hell
* I want to open the editor just by typing ch
to the terminal.
* So I create an symbolic link called ch
at the /usr/bin
directory.
ln -s /usr/share/code_like_hell/bin/code_like_hell /usr/bin/ch
hard link
Acts like a synchronized copy of the original file, change in one file changes the other.
# Hard link creations
ln FILENAME LINKNAME
cp -l FILENAME LINKNAME
Globbing and Wildcards
Glob patterns specify sets of filenames with wildcard characters. Wildcards are symbols with special meaning. It is especially useful when we don’t know the exact name or if we perhaps want to use more than one name to do something.
# Question Mark
? # Matches one character within one directory.
# Single Asterisk
* # Matches zero or more characters within one directory.
## Double Asterisk
** # Matches matches zero or more characters across multiple directories.
# Square Brackets Range
[a-dsu] # Matches one character from the range i.e. a,b,c,d,s,u
[3-7a-g]
# Square Brackets Group
[:digit:] # Equals to [0-9]
[:alpha:] # Equals to [a-zA-Z]
[:alnum:] # Equals to [0-9a-zA-Z]
[:upper:] # Equals to [A-Z]
[:lower:] # Equals to [a-z]
# Not containing anything from bracket
[!a] # Matches one character that is not letter a. Equivalent of [^ ] in RegEx.
# Examples
ls ?[[:digit:]]*
ls ?[4-6]
GNU Findutils
locate
locate -b -i -n 17 -S -u
find
find / -name "toBeFound" ACTIONS -delete -regex '.*anything.*' -type f d l s -ls -user -exec ls -l {} \; -size +-nc k M G -ok -empty -mindepth -maxdepth n -perm 400 u=rw -u=rmw /u=r,o=x -user USERNAME -group
Read files
# Create new (empty) file
touch path/to/my/newFileName.anything
# Output every line from file
cat file
# Output every line from file in reverse order
tac file
# Output first 5 lines from file in reverse order
head file
# Output first n lines from file in reverse order
head -n 3 file
# Output last 5 lines from file in reverse order
tail file
# Monitor a file as that other software writes to
tail -f
Standard input, standard output, standard error output (Stdin, stdout, stderr)
# 0< 1> >> 2>
# 1> where_to 2>&1
# &> where_to
# Take output of command and writes it to the file
# COMMAND > FILE
echo Hello world! > file_example.txt
# Take output of command and writes it at the end of file
# COMMAND >> APPENDED_FILE
echo Hello another world! >> file_example.txt
Pipe - command output redirection
Connects standard output of one command to the standard input of another command.
# any_command | sort, uniq, less, head
# tee
# file
# Sort output
sudo du -a | sort -n -r | head -n 20
Named pipes (Advanced)
mkfifo pipe2
ls > pipe2
cat < pipe2
Compare two files
Command diff
# Show differences of files FILE_A, FILE_B (e.g. "< UNIQUE LINE OF FILE_A")
diff FILE_A FILE_B
# Unified format - more information about the files, changes have a context
diff -u FILE_A FILE_B
# Compare file with a pipe redirection
SOME_COMMAND | diff FILE_A -
# Show non-printing characters
diff FILE_A FILE_B | cat -t
Show differences side by side (usually preferred, not always)
# Show differences side by side
diff --side-by-side --suppress-common-lines FILE_A FILE_B
# See the difference line by line with more command
diff -y --suppress-common-lines FILE_A FILE_B | more
# Get number of different lines
diff -y --suppress-common-lines FILE_A FILE_B | wc -l
Command cmp
cmp file1 file2
Linux Directory Structure
/bin |
Executables. |
/root |
Root user data. |
/home/* |
Other user data. |
/opt |
Optional software (things you can’t instal with package manager). |
/etc |
Configuration files, e.g. /etc/issue. |
/lib |
Shared libraries. |
Install Software
Every distribution family has its package manager. Debian based distributions have https://en.wikipedia.org/wiki/APT_(software). Arch based distros have https://en.wikipedia.org/wiki/Arch_Linux#Pacman.
Advanced Package Tool (apt)
Install a package using apt.
sudo apt install PACKAGE_NAME
The packages are looked up in source repositories specified in /etc/apt/sources.list and /etc/apt/sources.list.d/
Install from package .deb
Works the same way for an update.
sudo dpkg -i PACKAGE_NAME.deb
# attempt to fix corrupted dependencies
sudo apt-get install -f
Version of installed software
# Most of the programs have implemented option --version
COMMAND_NAME --version
Search for package
apt-cache search KEYWORD
Check if installed
dpkg-query -l 'someth'
User management and privileges
groupmod
whoami
who
groups
Add,delete user | group
adduser USERNAME
deluser USERNAME
groupadd GROUPNAME
goupdel GROUPNAME
Add user to group
usermod -a -G GROUP USER
Group information
Read file containing information about groups. Every line of the file has following structure:
GROUP_NAME:PASSWORD:GROUP_ID:GROUP_USER_1, GROUP_USER_2, GROUP_USER_3
less /etc/group
Change password
[sudo] passwd [username]
Switch user
su USERNAME
Every su opens a new shell.
# Show number of open shells
echo $SHLVL
Superuser
su
sudo su
sudo COMMAND
User permissions
Everything has permissions set.
ls -la
#drwxrwxrwx NUMBER USER USER NUMBER DATE NAME_OF_THE_FILE
- --- --- --- filemode user group others
+ d - directory + l - link + b - bloc type (harddisc) + c - chartype
Change permissions
chmod u-x rename needs directory privileges to read files directory needs r+x to rename files directory needs w+x --- 000 0 --x 001 1 -w- 010 2 -wx 011 3 r-- 100 4... chmod 755 text.txt chmod u=rw,g+rw ccc.txt
/etc/shadow
setuid bit chmod u+s ... 4777
setgid bit chmod g+s ... 2777
sticky bit chmod +t ... 1777
umask 0224 d- 777 f- 666
chown USER[:GROUP] OBJECT
Useful commands
# Path to the executable file i.e. command COMMAND
which COMMAND
# One line information
whatis COMMAND
# Equivalent to
man -f COMMAND
# Output stays into terminal after pressing q to quit
more
# File open in vim-like environment after pressing :q to quit the terminal is clean
less
xdg-open ANY_NAME.ANYTHING
# Split file into multiple n-lines files
split -l 100 FILE_NAME NEW_NAME
# Split file into 50MB files, with numerical suffix
split -d -b 50m data.csv data_ --additional-suffix='.csv'
# Proportionally split file into n files
split -n 3 filename a
# Change suffix length (by default 2 characters)
split -n 3 -a 5 filename
cat file_0* > merge # merges all the files named file_01 file_02 etc.
echo "First line" | cat - second_file # minus make the first file_stream from stdin
echo "first" | cat - lines > tmp && mv tmp lines # prepend "first" to lines file.
# Get the Nth column (numbered from 1), implicit separator is `tab`
cut -f 3 filename # get third column
cut -f 1,3 filename # enumerated columns
cut -f 2-3 filename # range of columns
cut -d ':' -f 1 /etc/password | head # define separator
cut -c 2-10 # extract characters (one character one column)
paste file1 file2 file3 #(implicitni oddelovac je TAB)
paste -d ':' file1 file2 file3 #(explicitni definice oddelovace)
paste -s file1 file2 file3 #(spoji obsahy jednotlivych souboru za sebou po radcich)
# Sort and merge multiple files
sort file1 file2 file3 > file
cut -d ':' -f 1 /etc/passwd | sort
sort -r file # sort in reverse order
sort -n file # Numeric sort not lexicographic
cut -d ':' -f 3 /etc/passwd | sort
cut -d ':' -f 3 /etc/passwd | sort -n
sort -k file # sort by k-th columns (separator is `tab` by default)
# (seradi numericky podle klice = od 5. sloupce v tabulce)
ls -l | sort -nr -k 5
# (razeni podle vice klicu)
sort --key=1,1 --key=2n filename
# (offset v ramci sloupce)
sort -k 3.7nbr -k 3.1nbr -k 3.4nbr filename
# (explicitni definice oddelovace)
sort -t ':' -k 7 /etc/passwd
# Get random N lines from input
shuf -n N input > output
wget https://static.boredpanda.com/blog/wp-content/uuuploads/cute-baby-animals/cute-baby-animals-2.jpg
sudo apt-get instal ranger # install ranger
ranger # start ranger
| key | action | | --- | --- | | j k | move up, move down | | h l | move level up, move into directory | | s | open terminal console | | zh | see hidden files and directories | | / n N | search, go to next, previous match |
# show height
tput lines
# show width
tput cols
Push process the background
"I have opened something with terminal, now i see the process and can not use the terminal anymore"
Situation as described is the single most common example when is super nice to push the process to the background.
How to do it?
Press Ctrl+Z, then type
bg
The proccess will continue in background.
If you want to bring the process back to the foreground, type
fg
pwd | xclip -selection clipboard
echo "scale=2; 3/2" | bc
echo "obase=10; ibase=2; 1101" | bc
date # Get current date
date -r FILE # Get last modification date of a file
date +%T.%N # Specify the datetime format (start with + for datetime format use %)
SSH
ssh USER@99.888.777.22
Copy files over ssh
scp [OPTION] [user@]SRC_HOST:]file1 [user@]DEST_HOST:]file2
scp -r compute USER@78.128.250.10:/home/USER/computing/
Screen
# How to use screen from terminal
screen # Create screen
screen -d # Detach from screen
screen -r # Reattach to screen
screen -ls # List all screens
# Kill screen
screen -X -S SESSION_ID_FROM_LS kill
How to work inside of a screen
Press Ctrl+a+OPTION
OPTION | Action |
---|---|
c |
create new bash |
" |
show open bash |
S |
devide horizontaly |
devide verticaly |
tab |
change region |
A |
rename region |
k |
kill actual screen |
X |
close region |
Q |
close regions |
esc |
SSHFS
Mount local direcotry to remote directory
sshfs $USER@remote.example.com:/home/$USER/code ~/remote_code
If user on local is different than the one logging with ssh
Uncomment user allow_other in /etc/fuse.conf
user_allow_other
sshfs -o allow_other user@myserver:/home/user/myprojects ~/mount/myprojects
Unmount
fusermount -u ~/mount/myprojects
Processes
top
ps aux | grep cat
# kill one specific precess id
kill -9 3827
# kill family of proceses
killall -9 chrome
Environments and variables
Variables and functions, can be exported (global) or not.
set
Can be used to set various shell options, or the positional parameters. If no arguments or options are given, then it prints all shell variables and functions.
echo ${...}
compgen -v
Outputs only names of all shell variables, exported or not.
GLOBAL: env, printenv …
# Export can be used to export variables or functions.
export
# With the -p option, it prints exported variables and functions
export -p
env
The env command can run other commands with modified environments. If no command is given, env prints environment variables (i.e., exported variables).
printenv
Prints environment variables.
LOCAL
set | grep ''
var_a=123a
# CONSTANTS
$USER; $PATH; $SHLVL; $SHELL;
# variables
name=value [[:alnum:]]
unset ... (local)
declare [-i; -r] ...
Open new shell
# Open (some) shell
bash # open bash
dash # open dash
sh # open shell
# Tell current shell language
echo $0
# See shell level
echo $SHLVL
# exit shell i.e. go to the previous enviroment
exit
bash child[sub] interactive / uninteractiv - | read
startup
login shell /etc/profile $HOME/ [.profile; .bash_profile; .bash_login] non-login shell /etc/.bashrc $HOME/.bashrc source
History
~/.bashrc
HISTSIZE=1000
HISTFILESIZE=10000
echo $HISTFILE
echo 'export HISTIGNORE="ls:tree:cat:tail:head:bash"' >> ~/.bashrc
history !111
press - ctrl+R - for searching of a commands from past
Text transformation
tr
# Example: Remove spaces from filename
ls # name\ with\ spaces.txt
for file in *; do mv "$file" `echo $file | tr ' ' '_'` ; done
ls # name_with_spaces.txt
Translate, squeeze, and/or delete characters from standard input, writing to standard output.
tr [OPTIONS] SET1 [SET2]
Translate charactes
Command expects arguments SET1 SET2
where SET1 are characters to be translated with SET2.
prikaz ocekava dva argumenty: sadu znaku, ktere ma nahradit a sadu znaku, kterymi je ma nahradit
sady znaku mohou byt vyjadreny tremi zpusoby
# Characters specified by enumeration
echo "characters" | tr abc 123
# Characters specified by range
echo "characters" | tr a-z 1-3
echo "chArACtERs" | tr a-z A-Z
# Characters specified by POSIX
echo "chArACtERs" | tr [:lower:] [:upper:]
# First range is shorter - nothing special
echo "aaabbbccc" | tr a-b 1-3
# First range is longer - characters from SET1 without partner are replaced with last form SET2
echo "aaabbbccc" | tr a-c 1-2
# remove characters
echo "aaabbbccc" | tr -d ab
# replace repetitions with one occurance
echo "aaabbbccc" | tr -s ab
echo "abcabcabc" | tr -s ab
Expansions
# wild cards * ? ' ' $
mv old/* new/
# paths \ . ..
ls ..
# brace expansion {}
mkdir task_{a,b,c} # mkdir task_a task_b task_c
mkdir task{01..03} # mkdir task01 task02 task03
# tilde expansion
ls ~/Documents # ls /home/$USER/Documents
# parameter and variable expansion
variable=10
echo ${variable} # echo 10
# command substitution
echo Hello \"$(ls)\" folders!
# arithmetic expansion + - * / % ** ++ --
echo $((1238 % 17)) echo 14
# word splitting
# filename expansion
# quote removal
Grep
Regular Expressions
“regex” or “regexp”? → /regexp?/
Command Line Editing
set -o vi
sed
The sed utility is a stream editor that shall read one or more text files, make editing changes according to a script of editing commands, and write the results to standard output. The script shall be obtained from either the script operand string or a combination of the option-arguments from the -e script and -f script_file options.
sed is a stream editor. A stream editor is used to perform basic text transformations on an input stream (a file or input from a pipeline). While in some ways similar to an editor which permits scripted edits (such as ed), sed works by making only one pass over the input(s), and is consequently more efficient. But it is sed’s ability to filter text in a pipeline which particularly distinguishes it from other types of editors.