Skip to content

Bash and PowerShell side by side

Practical 5.2 bash-and-powershell-side-by-side-annex.pdf · PDF

You talk to your grandmother in Catalan and to your English teacher in English. You never stop to ask "which language is better?". You ask "who am I talking to?". You are already bilingual.

A sysadmin is bilingual too. Linux servers speak Bash. Windows machines speak PowerShell. In a real company you meet both on the same day, often in the same hour. Today you say the same ten sentences in both languages — and you discover that the two shells do not just use different words: they think differently.

What you will learn

  • Translate everyday file commands between Bash and PowerShell (cp and Copy-Item, grep and Select-String...)
  • Solve the same task in both shells and check that both give the same result
  • Read a CSV file as text in Bash and as objects in PowerShell
  • Put a variable and a command's output inside a string in both shells
  • Why cut -d, -f2 can give a wrong answer without any error, and Import-Csv does not
  • Decide, with an example, when each shell is the more comfortable tool

Two languages, one job

In Back to the shell you rebuilt Bash: redirection, pipes, variables, globbing. In PowerShell first contact you met PowerShell: cmdlets named Verb-Noun, Get-Help, Get-Member, and a pipe that carries objects.

Today is translation. Keep the bilingual idea in mind all page: same meaning, different words, and sometimes a different grammar.

The method for the whole practical

You will not know every command by heart. Nobody does. Find it in this order:

  1. The dictionary below.
  2. The built-in help: man or --help in Bash, Get-Help in PowerShell.
  3. Your neighbour.
  4. The teacher, last.

The dictionary

Job Bash PowerShell
Where am I / go / list pwd · cd · ls Get-Location · Set-Location · Get-ChildItem
New folder mkdir -p a/b New-Item -ItemType Directory a\b
Write / append / read a file echo "x" > f · >> f · cat f Set-Content f "x" · Add-Content f "x" · Get-Content f
Copy / move or rename / delete cp · mv · rm -r Copy-Item · Move-Item, Rename-Item · Remove-Item -Recurse
Find files by name find dir -name "*.txt" Get-ChildItem dir -Recurse -Filter *.txt
Search text in a file grep text f Select-String text f
Sort / first n / count sort · head -n · wc -l Sort-Object · Select-Object -First n · Measure-Object
Count repeated values sort \| uniq -c Group-Object
Read a CSV cut -d, -f2 Import-Csv, then properties by name
Processes ps Get-Process
Variable x=5 · "$x" · $(cmd) $x = 5 · "$x" · $(cmd)

Look for patterns before you memorise anything:

  • Bash names are short and must be memorised. PowerShell names are long and can be guessed: if Get-Content reads a file, Set-Content probably writes one.
  • Both use |, $x and double quotes in the same way.
  • Assigning a variable is different: Bash wants no spaces and no $ (x=5). PowerShell wants the $ and allows spaces ($x = 5).

A worked example

"Show the first three lines of staff.csv."

Bash         head -3 staff.csv
PowerShell   Get-Content staff.csv -TotalCount 3

Same three lines on both screens. How would you have found -TotalCount? Not by knowing it: Get-Help Get-Content, read the list of parameters, and there it is. That is the method.

The traps of translation

Every bilingual person knows false friends: words that look the same but mean something else. The shells have them too.

Trap What happens The fix
mkdir -p tramuntana/{dev,design,admin} in PowerShell The braces are not expanded: you get one folder with a strange name PowerShell takes a list separated by commas: New-Item -ItemType Directory tramuntana\dev, tramuntana\design, tramuntana\admin
Rename-Item a\readme.txt a\dev\notes.txt Rename-Item wants a new name, not a new path Give only the name (notes.txt), or use Move-Item to move and rename at once
\ in paths PowerShell accepts both \ and / Bash accepts only /; there \ means "the next character is literal"
grep design on a line that says DESIGN grep is case-sensitive: no match grep -i. Select-String ignores case by default — same job, opposite defaults
Where-Object WorkingSet64 > 100MB In PowerShell > still means redirect: it creates a file called 100MB Compare with -gt (greater than)

Careful: text is bytes

In Windows PowerShell 5.1, "text" > file writes the file in UTF-16, two bytes per character. Remember from Unit 1: text is just bytes with an agreed encoding. A Linux tool reading that file later sees strange gaps between letters. Set-Content avoids the surprise.

Text or objects: the real difference

Here is where the two languages stop being a matter of vocabulary. Take one question: how many people are in each department?

The file staff.csv (from Back to the shell) starts like this:

user,dept,role,year
marta,dev,backend,2019
joan,design,ui,2020
tail -n +2 staff.csv | cut -d, -f2 | sort | uniq -c
      2 admin
      3 design
      7 dev

Bash sees text: lines of characters. You skip the header by hand (tail -n +2), cut column number 2, sort so that equal lines touch, then count neighbours.

Import-Csv staff.csv | Group-Object dept | Select-Object Name, Count
Name   Count
----   -----
dev        7
design     3
admin      2

Import-Csv reads the header and turns every line into an object with properties named user, dept, role and year. Group-Object groups equal values wherever they are, so no sort is needed.

flowchart LR
    subgraph BASH ["Bash: the pipe carries text"]
        direction LR
        B1["<b>tail</b><br>lines of characters"] -->|"text"| B2["<b>cut -f2</b><br>column by position"]
        B2 -->|"text"| B3["<b>sort + uniq -c</b><br>count neighbours"]
    end
    subgraph PS ["PowerShell: the pipe carries objects"]
        direction LR
        P1["<b>Import-Csv</b><br>one object per line"] -->|"objects"| P2["<b>Group-Object dept</b><br>property by name"]
        P2 -->|"objects"| P3["<b>Select-Object</b><br>Name, Count"]
    end

Now imagine a colleague adds a new first column to staff.csv, say an employee number. What breaks?

  • In Bash, -f2 now points at the wrong column. You get a wrong answer, and no error at all.
  • In PowerShell, dept is still called dept. The command keeps working.

That is the real advantage of objects: a name survives changes that break a position.

Careful: PowerShell is not Bash with longer words

The | looks the same in both shells, but it carries a different thing. In Bash the next command receives characters and must cut them up again. In PowerShell it receives the whole object, with every property — even those not shown on the screen.

So does PowerShell win? No. Bash works on any text at all: logs, configuration files, the output of a program written forty years ago. Nobody has to turn it into objects first.

Linux keeps its configuration in text files, so its shell is good with text. Windows keeps it behind programming interfaces, so its shell is good with objects. Each shell looks like its system.

Variables inside strings

The last task of the practical writes a small report file with today's date and a count. Both shells put a command's output in a variable with $( ), and both replace variables inside double quotes.

today=$(date +%F)
n=$(tail -n +2 staff.csv | wc -l)
echo "Report $today: $n people" > report-$today.txt
$today = Get-Date -Format yyyy-MM-dd
$n = (Import-Csv staff.csv).Count
"Report ${today}: $n people" | Set-Content "report-$today.txt"

The file contains a line like Report 2027-01-12: 12 people.

Look at the braces in ${today}. In PowerShell, $today: followed by text is read as a drive name (like C:), and the line fails. The braces mark exactly where the variable name ends. In Bash the colon is harmless.

To prove a folder is gone after deleting it, Bash just lists (ls); PowerShell can ask directly with Test-Path tramuntana, which answers True or False.

Practical 5.2

Open the Practical 5.2 sheet (the button at the top). You need deb-lab and win11 running at the same time, and staff.csv in a folder p41 in your home in both machines.

The ten tasks go from easy (where am I, create folders) to the ones where text and objects really differ (count per department, sort by year, list the processes using most memory). For each task, write in your Markdown report practical-5.2-surname.md:

  • the Bash command and the PowerShell command, each in a code block;
  • the output, pasted as text (not a screenshot of the whole desktop).

Finish with 4–6 lines of reflection: which shell for which job, with one example from the practical. The report goes on Google Classroom.

Two machines, one PC

deb-lab and win11 both want 4 GB of RAM. If your PC struggles, the teacher will tell you how to lower the memory of each VM for today.

Key takeaways

  • Bash and PowerShell do the same everyday jobs with different words: a dictionary plus man / Get-Help is all you need to translate.
  • Bash names are short and memorised; PowerShell cmdlets are long Verb-Noun names you can guess.
  • Watch the false friends: grep is case-sensitive and Select-String is not; > redirects in both shells; Rename-Item wants a name, not a path.
  • The Bash pipe carries text; the PowerShell pipe carries objects with named properties.
  • A column position (cut -f2) breaks silently when the file changes; a property name (dept) does not.
  • Neither shell is better: each one looks like its system — text files on Linux, programming interfaces on Windows.

Quick check

1. Which PowerShell cmdlet does the job of grep?
  • Get-Content
  • Select-String
  • Where-Object
  • Get-ChildItem

Select-String searches for text inside files, like grep. One difference: it ignores upper and lower case by default, while grep needs -i for that.

2. Which Bash pipeline does the same job as Import-Csv staff.csv | Group-Object dept?
  • grep dept staff.csv
  • sort staff.csv | head
  • wc -l staff.csv
  • cut -d, -f2 staff.csv | sort | uniq -c

cut keeps the department column, sort puts equal values next to each other, and uniq -c counts them. Group-Object does the whole job in one step because it works on the property dept.

3. Why does Group-Object not need a sort before it, when uniq -c does?
  • It groups equal values wherever they are in the input
  • CSV files are always sorted when they are saved
  • PowerShell sorts every pipeline automatically
  • It only looks at the first line of the file

uniq -c only joins equal lines that are neighbours, so Bash must sort first. Group-Object collects all objects with the same value, no matter where they appear.

4. A line of staff.csv says DESIGN in capitals. Who finds it: grep design staff.csv or Select-String design staff.csv?
  • Both of them
  • Only grep
  • Only Select-String
  • Neither of them

grep is case-sensitive: design does not match DESIGN unless you add -i. Select-String ignores case by default. Same job, opposite defaults.

5. A colleague adds a new first column to staff.csv. Which command still gives the departments?
  • cut -d, -f2 staff.csv
  • (Import-Csv staff.csv).dept
  • tail -n +2 staff.csv | cut -d, -f2
  • head -3 staff.csv

After the change, column 2 is the user name, so every cut -f2 gives a wrong answer without an error. Import-Csv reads the header and finds the property by name, so dept is still dept.

6. In PowerShell, “Report $today: $n people” fails. What fixes it?
  • Writing ${today} so the variable name ends before the colon
  • Using single quotes instead of double quotes
  • Removing the $ from both variables
  • Putting spaces around the = when assigning today

PowerShell reads $today: as a drive name, like C:. The braces in ${today} mark where the name ends. Single quotes would print $today literally, which is not what you want.

7. You must count error lines in a 40-year-old program's plain-text log on a Linux server. Select the two that are true.
  • Bash tools like grep and wc work on it directly
  • The log is text, so nobody has turned it into objects
  • PowerShell is needed because the log has no header
  • Bash must convert it to CSV before it can count

Bash is at home with text: grep error app.log | wc -l works on any text file, whoever wrote it. PowerShell shines when data comes as objects; a plain log has none until someone parses it.

Next: you already know the people behind the Linux prompt. Now create them on Windows, with the GUI and with PowerShell, in Users and groups on Windows.