Command Line: Level 2 (Intermediate)

The next step up at the terminal: variables, loops, conditionals, your first scripts, and sed and awk for real file formats, all taught gently and at your own pace.

🟡 Intermediate ⏱️ ~2 hr 💻 Bash

You are ready for this if...

You have finished Command-Line Basics and you can move around folders, look inside files, and use grep and the pipe |. If that still feels new, go back and practise first. There is no rush here.

No memorizing needed. Type each command at your own terminal, change something, run it again. That is the whole method. Keep this page open as a reference whenever you need it.

1. Variables and quoting

A variable is just a name for a value. Set it with = (no spaces), and read it back with $.

name="genes.fasta"
echo "$name"              # prints: genes.fasta
echo "I am in $PWD"        # $PWD is the current folder

Always quote your variables

Write "$name", not $name. The quotes keep filenames with spaces in one piece. Forgetting them is the single most common beginner bug in shell scripts.

2. Capture a command's output

Command substitution with $( ) runs a command and hands you its result to store or print.

count=$(grep -c ">" genes.fasta)
echo "The file has $count sequences"

3. Loops: the same job on many files

a.fasta b.fasta c.fasta grep -c ">" "$f" the same command, each file 3 counts
A for loop applies one command to every file in turn, however many there are.

This is where the terminal starts to save real time. A for loop repeats a command for every item you give it.

for f in *.fasta; do
    echo "$f has $(grep -c '>' "$f") sequences"
done

Read it as a sentence

"For each file f ending in .fasta, do this, then move to the next." One instruction, applied to every matching file, however many there are.

4. Making decisions: if and test

if [ -f genes.fasta ]; then
    echo "the file is here"
else
    echo "missing"
fi

Handy tests

[ -f file ] is true if a file exists, [ -d folder ] for a directory, and [ -z "$x" ] if a string is empty. Mind the spaces inside the brackets: they are required.

5. Writing a script you can run

7 5 5 rwx r-x r-x owner group everyone else read = 4, write = 2, execute = 1 (4+2+1 = 7, 4+1 = 5)
Permissions in one picture: 755 gives the owner full rights (rwx), and everyone else read and execute (r-x).

Put commands in a .sh file and you have a reusable tool. The first line (the "shebang") tells the system to run it with bash.

# file: count_seqs.sh
#!/bin/bash
# count sequences in the FASTA file given as the first argument
grep -c ">" "$1"

Then make it executable and run it:

chmod +x count_seqs.sh
./count_seqs.sh genes.fasta

What "permissions" mean

chmod +x marks a file as runnable. Those number codes you see (like chmod 755) are just read = 4, write = 2, execute = 1 added up for the owner, group, and everyone else. 755 means the owner can do everything and others can read and run.

6. sed and awk: editing text and columns

Two classic tools that handle most text wrangling. sed does find-and-replace; awk works with columns, which is perfect for table formats like BED, VCF, and GTF.

# sed: strip the leading ">" from FASTA headers
grep ">" genes.fasta | sed 's/>//'

# awk: print columns 1 and 3 of a table (e.g. a BED file)
awk '{print $1, $3}' regions.bed

# awk: keep only rows where column 3 is above 1000
awk '$3 > 1000' regions.bed

Why awk is everywhere in bioinformatics

So many formats are just columns of tab-separated data. awk lets you pick columns, filter rows, and do quick maths on them without opening anything. A little awk replaces a lot of manual work.

7. Finding files: find and xargs optional on first pass

find . -name "*.fastq"          # every FASTQ in this folder and below
find . -name "*.sam" | xargs rm   # feed the results to another command (careful: rm!)

Look before you delete

A find ... | xargs rm deletes every match with no undo. Run the find on its own first to see exactly what it lists, then add the rm.

8. Getting data and unpacking it optional on first pass

wget https://example.org/data.tar.gz   # download a file (or: curl -O ...)
tar -xzf data.tar.gz                    # unpack a .tar.gz archive
gunzip reads.fastq.gz                  # unzip a single .gz file

When something runs too long

Check what is running with top (press q to quit) or ps, and stop a stuck command with Ctrl-C. Big sequencing files can take a while; that is normal.

Practice exercises

Try each at your own terminal before opening the solution.

Exercise 1: loop over files. Print the name of every .fasta file in the current folder.

Show a worked solution
for f in *.fasta; do
    echo "$f"
done

Exercise 2: count reads in a FASTQ. Store the line count of reads.fastq in a variable, then print the number of reads (lines divided by 4).

Show a worked solution
n=$(wc -l < reads.fastq)
echo $(( n / 4 ))

Exercise 3: pick a column. Use awk to print just the second column of a table called table.txt.

Show a worked solution
awk '{print $2}' table.txt

Check yourself

R and the terminal do not run in this page, so here is what correct output looks like. Type each one and compare.

You typeYou should see
count=$(grep -c ">" genes.fasta); echo $countthe sequence count
echo $(( $(wc -l < reads.fastq) / 4 ))the number of reads
awk '{print $2}' table.txtthe second column

Check your understanding

What does awk '{print $2}' table.txt do?
Right. In awk, $2 is the second field (column) of each line.
What does the first line of a script, #!/bin/bash (the "shebang"), do?
Correct. The shebang names the interpreter, so ./script.sh knows to run with bash.
You want every .fastq file in this folder and all folders below it. Which command?
Right. find searches recursively down the folder tree; ls *.fastq only looks in the current folder.
Your loop for f in *.fasta; do mv $f data/; done fails on a file named my reads.fasta. What is the fix?
Right. Without quotes the shell splits my reads.fasta into two words. "$f" keeps the filename whole.
What does count=$(grep -c ">" genes.fasta) do?
$( ) runs the command inside and hands back its output, which you then store in the variable.
Why write "$f" with quotes inside a loop?
Without quotes, a filename like my reads.fastq would be split into two pieces. Quoting keeps it whole.
What does chmod +x script.sh do?
The +x adds the "execute" permission, which a file needs before the shell will run it as a program.
Put these skills to work on a real file

Project: wrangle a real data file from the command line →

Level 3 (Advanced): script functions, safe error handling, parallel jobs, and working on a remote server is coming next.