Bash Index : C - The 'C' Bash commands : description, flags and examples


Usage :

change directory, i.e. move into another directory

cd has some default behaviors :

Command ... Is interpreted as ... Comments
cd cd $HOME
cd - cd "$OLDPWD" && pwd If you don't want the original directory name to be displayed, use cd "$OLDPWD" instead of cd -


Usage :

comm [options] file1 file2

To find lines common to 2 files :
  1. sort file contents
  2. remove duplicates
  3. comm -12 file1 file2

Flags :

Flag Usage
-1 suppress column 1, i.e. display lines unique to file2 and common lines
-2 suppress column 2, i.e. display lines unique to file1 and common lines
-3 suppress column 3, i.e. display lines unique to file1 and lines unique to file2 (i.e. hide common lines)

Example :

Trying all -1, -2 and -3 options at once :

tmpFile1=$(mktemp); tmpFile2=$(mktemp); echo 'FILE1' > "$tmpFile1"; echo 'FILE2' > "$tmpFile2"; for i in {1..3}; do echo "line $i" >> "$tmpFile1"; done; for i in {3..5}; do echo "line $i" >> "$tmpFile2"; done; cat "$tmpFile1" "$tmpFile2"; for mode in 1 2 3 12; do echo -e "\n'-$mode' mode :"; comm -$mode "$tmpFile1" "$tmpFile2"; done; rm "$tmpFile1" "$tmpFile2"

FILE1			result of cat file1 file2
line 1
line 2
line 3
line 3
line 4
line 5

'-1' mode :
	line 3		this line is common to both files, others are unique to file2
line 4
line 5

'-2' mode :
line 1
line 2
	line 3		this line is common to both files, others are unique to file1

'-3' mode :		common lines are hidden
line 1
line 2
	line 4
	line 5

'-12' mode :		displaying only common lines
line 3


Usage :

Cruft is a Debianoid tool to look over your system : It is available as package cruft in the Debian archive.

Flags :

Flag Usage
-r reportFile Output report to reportFile instead of standard output.
this option is recommended since output can be VERY verbose


Usage :

change file mode bits (i.e. permissions)

Flags :

Flag Usage
-R --recursive change files and directories recursively
--reference=referenceFile apply permissions like those of referenceFile (see also chown's --reference)

Example :

testFile=$(mktemp --tmpdir playingWithFilePermissions.XXXXXXXX); ls -l "$testFile"; chmod o=wr "$testFile"; ls -l "$testFile"; chmod o-w+x "$testFile"; ls -l "$testFile"; chmod 777 "$testFile"; ls -l "$testFile"; chmod g=--- "$testFile"; ls -l "$testFile"; rm "$testFile"

-rw------- 1 stuart users 0 Mar	8 16:41 /tmp/playingWithFilePermissions.50YC1hqb		default permissions for new file
-rw----rw- 1 stuart users 0 Mar	8 16:41 /tmp/playingWithFilePermissions.50YC1hqb		made by chmod o=rw
-rw----r-x 1 stuart users 0 Mar	8 16:41 /tmp/playingWithFilePermissions.50YC1hqb		made by chmod o-w+x
-rwxrwxrwx 1 stuart users 0 Mar	8 16:41 /tmp/playingWithFilePermissions.50YC1hqb		made by chmod 777
-rwx---rwx 1 stuart users 0 Mar	8 16:41 /tmp/playingWithFilePermissions.50YC1hqb		made by chmod g=---


Usage :

run command or interactive shell with special root directory "/". Once done, leave with exit.

This command allow many hacks. One of them is changing a user's password while running a machine in "rescue" mode.
In such mode, after the machine has been rebooted via a "Live CD" (or anything similar), its "/" filesystem is mounted as /mnt/something. There are situations where you need to change a user (or root) password, then boot the server normally and log in (with password, since SSH keys are not available...) to investigate.

To do so (as root in rescue mode) :
  1. chroot /mnt/something
  2. passwd
  3. reboot in normal mode
  4. log in as root with the password you've just set
  5. debug / fix what needs to be debugged / fixed
  6. don't forget to restore the root account to its initial state, or at least to lock it.


Usage :

Setup cryptographic volumes for dm-crypt

Flags :

Flag Usage
-c cipher --cipher cipher Use the cipher encryption algorithm
-h hashingAlgorithm --hash hashingAlgorithm use hashingAlgorithm for passphrase hashing
-s numBits --key-size numBits use a numBits bits long key

Example :

cryptsetup luksFormat ...
set up a new dm-crypt device in LUKS encryption mode
cryptsetup luksOpen ...
open an existing dm-crypt device
cryptsetup luksClose ...
close a dm-crypt device
cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1       753287 iterations per second
PBKDF2-sha256     407055 iterations per second
PBKDF2-sha512     324435 iterations per second
PBKDF2-ripemd160  512000 iterations per second
PBKDF2-whirlpool  158299 iterations per second
#  Algorithm | Key |  Encryption |  Decryption
     aes-cbc   128b   167.4 MiB/s   187.6 MiB/s
 serpent-cbc   128b    74.9 MiB/s   213.3 MiB/s
 twofish-cbc   128b   179.5 MiB/s   236.5 MiB/s
     aes-cbc   256b   129.2 MiB/s   141.6 MiB/s
 serpent-cbc   256b    85.6 MiB/s   215.2 MiB/s
 twofish-cbc   256b   185.8 MiB/s   233.7 MiB/s
     aes-xts   256b   175.6 MiB/s   182.9 MiB/s
 serpent-xts   256b   196.6 MiB/s   199.1 MiB/s
 twofish-xts   256b   216.0 MiB/s   215.0 MiB/s
     aes-xts   512b   134.8 MiB/s   136.1 MiB/s
 serpent-xts   512b   195.7 MiB/s   199.9 MiB/s
 twofish-xts   512b   216.5 MiB/s   214.0 MiB/s
	For actual encryption, you will want XTS, which has been designed to support disk encryption efficiently.
	- In terms of the cipher alone, Serpent is generally agreed upon to be the most secure common cipher for LUKS.
	- (...) assuming you don't have national secrets or sensitive corporate data on your PC, AES-XTS-PLAIN is expected to be resistant for a reasonable timeframe against an attacker.

	==> serpent-xts-256 ?


Usage :

man cat says concatenate files and print on the standard output. This utility actually has more usages :
  1. effectively concatenate files : cat file1 file2 file3 > resultFile
  2. quickly display the contents of a single file : cat someFile
    this proves useful only when someFile is shorter than the number of lines your terminal can display. Otherwise, you'll only see the yourTerminalHeight trailing lines of someFile. In such case, less, head or tail might be good candidates.

    Please, please, PLEASE, don't fall in the useless-uses-of-cat n00b-trap !

  3. "burn" the contents of an .iso image onto a USB key / storage card to boot from and install a new operating system

Useless use of cat (aka UUOC) :

We ALL did it, but now, the cat ... | ... construct should ring the bell of uselessness and waste of resources (even though modern computers have so much CPUs and GB of RAM to waste that such commands will pass unsuspected ).

Actually, any extra | induces an additional process fork, which is an expensive CPU-time operation (especially on loops). Moreover, cat someFile | ... reads the whole file before piping it to the 2nd command, which delays its execution for big files.

Usage DON'T DO
View the contents of file, which is longer that your terminal height cat file | less less file
View the lines of file matching pattern cat file | grep pattern
cat file | head pattern
cat file | tail pattern
grep pattern file
head pattern file
tail pattern file
Read file line by line cat file | while read line; do echo $line; done while read line; do echo $line; done < file
Alter the lines of file matching pattern cat file | awk '/pattern/ {doSomething}'
cat file | sed 'sed' options
awk '/pattern/ {doSomething}' file
sed 'sed' options file
Extract a field (i.e. a column) from file cat file | cut 'cut' options cut 'cut' options file

Flags :

Flag Usage
-n --number number all output lines


Usage :

Copy files and directories

Flags :

Flag Usage
-a --archive same as -dR --preserve=all
=	-d					-R	--preserve=all
=	--no-dereference --preserve=links	-R	--preserve=all
=	--no-dereference -R --preserve=all
To copy the full contents of a directory, as is, into another :
cp -av sourceDir/* destinationDir
--backup[=backupOption] Instead of overwriting the destination file, make it a "backup" copy. The behavior depends on the value of backupOption :
  • (none) : make simple backups (i.e. only 1 backup, with either the default or the specified suffix)
    -b is equivalent to --backup with no backupOption
  • none, off : never make backups
  • numbered, t : make numbered backups. Will create 1 new backup every time, with incrementing suffix : .~1~, .~2~, ...
  • ...
see examples
-d same as --no-dereference --preserve=links
-f --force (details)
-P --no-dereference never follow symbolic links in sourceDir (i.e. copy the link, not its target)
-p --preserve preserve default attributes (see below)
--preserve=attributeList preserve the attributes specified with attributeList :
  • default attributes : mode, ownership, timestamps
  • additional attributes : context, links, xattr, all
-R -r --recursive copy directories recursively
-S suffix --suffix=suffix set the backup suffix (default : ~). works only with simple backups see examples
-s --symbolic-link make a symbolic link instead of copying. These commands are equivalent :
  • cp -s regularFile resultingSymlink
  • ln -s regularFile resultingSymlink
-v --verbose explain what is being done

More about cp -f :

man cp says : if an existing destination file cannot be opened, remove it and try again (this option is ignored when the -n option is also used)
The final part (between parenthesis) is clear (-n disables -f), so let's concentrate on the beginning :

if an existing destination file cannot be opened, remove it and try again says : If a file descriptor for a destination file cannot be obtained, attempt to unlink the destination file and proceed. It also gives the detailed procedure :

  • when sourceFile is a regular file
  • and when destinationFile exists
  • if a file descriptor for destinationFile can be obtained via actions such as open() (i.e. if destinationFile is writable by the current user)
    • THEN copy sourceFile into destinationFile
    • OTHERWISE delete destinationFile (if enough privileges to do so), then copy sourceFile as destinationFile

Check it :
touch file1; echo -e '\nRound 1'; cp file1 file2; echo -e '\nRound 2'; cp file1 file2; echo -e '\nRound 3'; chmod 200 file2; cp file1 file2; echo -e '\nRound 4a'; chmod 400 file2; cp file1 file2; echo -e '\nRound 4b'; cp -f file1 file2; echo -e '\nRound 5a'; chmod 000 file2; cp file1 file2; echo -e '\nRound 5b'; cp -f file1 file2; rm file[12]
Round 1		file2 didn't exist already, so that was easy !

Round 2		Piece of cake !!!

Round 3		w bit is set, no need to force

Round 4a
cp: cannot create regular file ‘file2’: Permission denied

Round 4b	w bit is NOT set, -f required

Round 5a
cp: cannot create regular file ‘file2’: Permission denied

Round 5b	no permission bit is set, -f required

Now if I try with file2 being a file I don't own, and on which I only have read permission (r--) :

cp file1 file2; cp -f file1 file2
cp: cannot create regular file ‘file2’: Permission denied
cp: cannot remove ‘file2’: Operation not permitted

As a conclusion, the -f / --force cp flag only serves to overwrite my own files if I have denied myself write access on them.

More about --backup and suffix :

Make a backup of an existing destination :
touch myFile; cp myFile myFile_COPY; cp -b myFile myFile_COPY; ls -1; rm myFile*
The default options do not overwrite the backup :
echo initial > myFile; cp myFile myFile_COPY; cp -b myFile myFile_COPY; echo modified > myFile; cp -b myFile myFile_COPY; ls -1; cat myFile myFile_COPY myFile_COPY~; rm myFile*
initial		contents of myFile_COPY~
Make numbered backups :
echo 'initial version' > myFile; cp --backup=numbered myFile myFile_COPY; for i in {1..5}; do echo "edit $i" > myFile; cp --backup=numbered myFile myFile_COPY; done; for i in myFile*; do echo -en "$i :|"; cat "$i"; done | column -s '|' -t; rm myFile*
myFile :           edit 5
myFile_COPY :      edit 5
myFile_COPY.~1~ :  initial version
myFile_COPY.~2~ :  edit 1
myFile_COPY.~3~ :  edit 2
myFile_COPY.~4~ :  edit 3
myFile_COPY.~5~ :  edit 4
Make suffixed backups :
touch myFile; cp myFile myFile_COPY; cp -b --suffix='_OLD' myFile myFile_COPY; ls -1; rm myFile*


Usage :

continue n returns to the top of the smallest enclosing for, while, or until loop, or to the top of the nth enclosing loop, if n is specified (defaults to 1).

Example :

Basic example : interrupting a single for loop :

#!/usr/bin/env bash

for i in {1..2}; do
	echo $i
	echo 'this will never be executed'
displays :

2 nested for loops :

#!/usr/bin/env bash

for i in {1..2}; do
	for j in {a..b}; do
		echo $i$j
		echo 'this will never be executed'
displays :

2 nested for loops and continue 2 :

#!/usr/bin/env bash

for i in {1..2}; do
	for j in {a..b}; do
		echo $i$j
		continue 2
		echo 'this will never be executed'
displays :


Usage :

Display data as columns

Flags :

Flag Usage
-c n Use up to n characters-wide screen space to display data (get a terminal window's width and height)
-s char -t Consider char as the column separator in the input, then display data as columns
-t Determine the number of columns the input contains and create a table. Columns are delimited with whitespace, by default, or with the characters supplied with -s.

Example :

for i in {1..3}; do echo col1_$i col2_$i; done | column -c 40
col1_1 col2_1	col1_3 col2_3
col1_2 col2_2
for i in {1..3}; do echo col1_$i col2_$i; done | column -t
col1_1	col2_1
col1_2	col2_2
col1_3	col2_3
for i in {1..3}; do echo col1_$i col2_$i; done | column -s 'l' -t
co	1_1 co	2_1
co	1_2 co	2_2
co	1_3 co	2_3


crontab reference header :

# +--------- Minute (0-59)                  | Output Dumper: >/dev/null 2>&1
# | +------- Hour (0-23)                    | Multiple Values Use Commas: 3,12,47
# | | +----- Day Of Month (1-31)            | Do every X intervals: */X -> Example: */15 * * * * Is every 15 minutes
# | | | +--- Month (1 -12)                  | Aliases: @reboot -> Run once at startup
# | | | | +- Day Of Week (0-6) (Sunday = 0) |	@hourly; @daily; @weekly
# | | | | |                                 |	@monthly; @yearly


crontab is used to :

  • submit jobs definition files to cron
  • list the contents of a crontab (personal or different user)
crontab option Description
-e edit the crontab with EDITOR
-l list registered jobs (view the crontab)
-r remove the crontab
-u kevin work on kevin's crontab
crontab fileName register filename as the new crontab

Unless explicitly specified with -u, all crontab ... commands apply to the current user.

crontab works so that you cannot append a new job at the end of a table. Instead, you have to :

  1. extract the whole content of the table into a file :
    • for the current user : crontab -l > /tmp/crontab
    • as root, for the user bob : crontab -l -u bob > /tmp/crontab.bob
    You can also launch edition with vi at the same time with the -e option. If no crontab is available, just create a new text file and go to the next step.
  2. edit the file to add/modify/delete jobs with your favorite text editor. The file MUST end with a blank line.
  3. register the new crontab :
    • for the current user : crontab /tmp/crontab
    • as root, for the user bob : crontab -u bob /tmp/crontab.bob
    This overwrites the previous crontab.

On Debianoids, failed CRON tasks are usually logged in /var/log/syslog, /var/log/cron or /var/log/messages (details).
Looks like there's no concern about them appearing all uppercase in the log files : /USR/SBIN/CRON


Each crontab entry consists of only six fields :

  • The first 5 represent the time the job should be executed and represent the following units, respectively :
    • minutes (0-59)
    • hour (0-23)
    • day of the month (1-31)
    • month of the year (1-12)
    • day of the week (0-7, 0 and 7 are for Sunday)
    Those 5 fields can be replaced by an alias such as @hourly, @daily, @weekly, ...
  • the 6th field is the actual command
Fields are separated by either space or tab.

Providing values :
  • To specify all possible values, use an asterisk *. You can specify a single value simply by including that one value. For example, the second line in the previous example has a value of 10 in the first field, meaning 10 minutes after the hour. Because all of the other 4 time fields are asterisks, this means that the command is run every hour of every day at 10 minutes past the hour.
  • Ranges of values are composed of the first value, a dash -, and the ending value. For example, the 4th line (example above) has a range 1-5 in the day of the week column, meaning that the command is only executed on days 1-5, i.e. Monday through Friday.
  • To specify different values that are not within a range, separate the individual values by a column ,. In the 4th example, the hour field has the two values 10 and 14. This means that the command is run at 10 a.m. and 2 p.m.

Note that times are additive. Let's look at an example :

10 * 1,16 * 1-5 /usr/local/bin/command

The command is run 10 minutes after every hour on the 1st and 16th, as well as Monday through Friday. If either the first or the sixteenth were on a weekend, the command would still run because the day of the month field would apply. However, this does not mean that if the first is a Monday, the command is run twice.

Remember : When specifying both the month day and the week day, the expression matches when one of both is true. If both are true, the command is executed only once.

The crontab entry can be defined to run at different intervals than just every hour or every day. The granularity can be specified to every two minutes or every three hours without having to put each individual entry in the crontab.

Let's say we wanted to run the previous command not at 10 minutes after the hour, but every ten minutes. We could make an entry that looked like this :
0,10,20,30,40,50	*	1,16	*	1-5	/usr/local/bin/command
This runs every 10 minutes: at the top of the hour, 10 minutes after, 20 minutes after, and so on. To make life easier, we could simply create the entry like this :
*/10	*	1,16	*	1-5	/usr/local/bin/command
The /n says that within the specific interval (in this case, every minute), run the command every n minutes; in this case, every 10 minutes.
We can also use this even when we specify a range. For example, if the job was only supposed to run between 20 minutes after the hour and 40 minutes after the hour, the entry might look like this :
20-40	*	1,16	*	1-5	/usr/local/bin/command
What if you wanted it to run at these times, but only every three minutes? The line might look like this :
20-40/3	*	1,16	*	1-5	/usr/local/bin/command
To make things even more complicated, you could say that you wanted the command to run every two minutes between the hour and 20 minutes after, every three minutes between 20 and 40 minutes after, then every 5 minutes between 40 minutes after and the hour :
0-20/2,21-40/3,41-59/5	*	1,16	*	1-5	/usr/local/bin/command
To make the fun last longer, let's imagine you have 2 jobs you want to execute every 2 minutes (source) :
  • jobEven on even minutes : 2, 4, 6, ..., 58, 00
  • jobOdd on odd minutes : 1, 3, 5, ..., 59
*/2	*	*	*	*	jobEven
1-59/2	*	*	*	*	jobOdd
And what if I want a job to run every n minutes with jobExecutionMinute % n != 0 ? (source)

Instead of :

1,6,11,16,21,26,31,36,41,46,51,56 * * * * /my/script
3,13,23,33,43,53 * * * * /my/other/script
you can do :
1-56/5 * * * * /my/script
3-53/10 * * * * /my/other/script

Remember :
  • Syntax : start-stop/increment
  • Ranges are inclusive : start and stop values are part of the range.

Error management

With the exception of certain errors in the time fields, errors are not reported until CRON runs the command. All error messages and output are mailed to the crontab owner (or to any address specified with, unless they are silenced by redirecting stdout and stderr to /dev/null with >/dev/null 2>&1.

Even though completely silencing stdout and stderr by sending them to /dev/null looks tempting, this may not be a wise idea. If tasks generate too much jabber, you'd better fix your scripts or run tasks less frequently.

Output is mailed to the user because there is no real terminal on which the cronjobs are being executed. Therefore, there is no screen to display the errors. Also, there is no keyboard to accept input. Does that mean you cannot give input to a CRON job? No. Think back to the discussion on shell scripts. We can redefine stdin, stdout and stderr. This way they can all point to files and behave as we expect.

Keep in mind that CRON is not exact. It synchronizes itself to the top of each minute. On a busy system in which you loose clock ticks, jobs may not be executed until a couple minutes after the scheduled time. In addition, there may be other processes with higher priorities that delay CRON jobs. In some cases, (particularly on very busy systems) jobs might end up being skipped if they are run every minute.

Did CRON task finish ok ? See logs :

  • /var/log/cron
  • /var/log/cronexecutionDate

View all users' crontabs :

  • for user in $(cut -d : -f1 /etc/passwd); do echo $user"'s CRONTAB :"; crontab -l -u $user; done | less
  • or, as root : less /var/spool/cron/crontabs/*

    /var/spool/cron/crontabs/* files are not intended to be edited directly. Use the crontab utility to edit CRON jobs.

Set your favorite editor to update crontabs :

Monthly reboot :

# 1st monday of month at 6h30
30 6 * * 1 [ $(/bin/date +\%d) -lt 8 ] && /sbin/init 6

# Last wednesday of every month, at 6h30
#30 6 * * 3 [[ $(date +\%d) == $(echo "$(echo "$(cal -s )"|awk '{print $4}')"|tail -1) ]] && /sbin/init 6

# not tested yet


Flags :

Flag Usage
-h --no-dereference Affect symlink instead of changing owner/group of its target
-R --recursive operate on files and directories recursively
--reference=referenceFile change owner + group like those of referenceFile (see also chmod's --reference)

Example :

chmod go-rwx myFile


Usage :

chkconfig has been obsoleted by systemd and systemctl.

Flags :

Flag Usage
--add serviceName add a new service for management
--del serviceName Unregister serviceName from chkconfig service management
--list serviceName
List all the registered daemons and their runlevel activation status
List the runlevel activation status for serviceName only.
-s daemon on|off [level]
Set the specified daemon ON or OFF for the specified runlevel. If no level is specified, the on/off is applied to ALL runlevels (?).
ex : chkconfig -s smb on

Example :

List daemons with ON/OFF status for each runlevel :

  • chkconfig --list
  • chkconfig --list httpd

Enable / disable daemon on given runlevels :

These commands enable / disable daemons, but they don't start / stop them.

  • chkconfig --level 345 nscd off
  • chkconfig --level 3 httpd on

If no runlevel is specified, then all the possible runlevels are impacted :

chkconfig iptables off
chkconfig --list iptables
iptables	0:off	1:off	2:off	3:off	4:off	5:off	6:off
chkconfig iptables on
chkconfig --list iptables
iptables	0:off	1:off	2:on	3:on	4:on	5:on	6:off

Query a daemon activation status :

chkconfig iptables returns a Unix success / failure if iptables is enabled / disabled in the current runlevel :
chkconfig iptables off; chkconfig iptables; echo $?; chkconfig iptables on; chkconfig iptables; echo $?

When chkconfig complains error reading info for serviceName :

This happens :
  • when listing services : chkconfig --list 2>&1 | less
  • when taking actions on serviceName : chkconfig --del serviceName

In my case, this was caused by a broken link :

/etc/init.d/serviceName -> /installDir/serviceName/bin/scripts/
Solution : fix this symlink (delete it if applicable, change target when possible)

How to specify runlevels and start/stop priority from within /etc/init.d/scriptName :

  1. add 2 commented lines in the header of scriptName :
    # chkconfig: runlevels startPriority stopPriority
    # description: description
    • runlevels : list of runlevels on which this script should start by default. To mean "none", just indicate -.
    • startPriority : (explicit)
    • stopPriority : (explicit)
    • description : (explicit) This can span on multiple lines with a trailing \ on each continued line.
  2. copy the script as /etc/init.d/scriptName
  3. register this new script : chkconfig --add scriptName
    This will create the appropriate symlinks :
    • /etc/rc.d/rcrunlevel.d/KstopPriorityscriptName -> ../init.d/scriptName
    • /etc/rc.d/rcrunlevel.d/SstartPriorityscriptName -> ../init.d/scriptName


Usage :

change file attributes. These attributes can be :

Flags :

Flag Usage
-d target is a directory, not a regular file.

Example :

Set a file immutable :
chattr +i myFile
Remove the immutable flag from a file :
chattr -i myFile
Set a directory immutable :
chattr -d +i myDirectory
Remove the immutable flag from a directory :
chattr -d -i myDirectory


Usage :

cut [options] file

Read file (or stdin if file is "-") line by line and display only the selected bytes, characters or fields.

Flags :

Flag Usage
-b n display the nth byte
specify numeric arguments
-c n display the nth character
specify numeric arguments, examples
-d character use character as field delimiter, defaults to TAB
-f n display the nth field
specify numeric arguments
--output-delimiter=string use string as the output delimiter. Defaults to the input delimiter, i.e. the value of -d

Numeric arguments for -b, -c and -f :

These apply to byte, character or field, depending on which flag is used.
  • n : nth, counted from 1
  • n- : from nth to end of line
  • n-m : from nth to mth (included)
  • -m : from first to mth (included)
  • x,y,z : the xth, the yth and the zth
    the data fields will be displayed following the order they have in the input, not the order you list them

Example :

Basic examples

echo 'aze rty uio' | cut -d ' ' -f 2,3
rty uio
echo a,b,c | cut -d ',' -f2,3
echo a,b,c | cut -d ',' -f2,3 --output-delimiter=' '
b c

Select characters :

echo hello | cut -c 2
echo hello | cut -c -2
echo hello | cut -c 2-