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 (
cpandCopy-Item,grepandSelect-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, -f2can give a wrong answer without any error, andImport-Csvdoes 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:
- The dictionary below.
- The built-in help:
manor--helpin Bash,Get-Helpin PowerShell. - Your neighbour.
- 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-Contentreads a file,Set-Contentprobably writes one. - Both use
|,$xand 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."
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:
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 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,
-f2now points at the wrong column. You get a wrong answer, and no error at all. - In PowerShell,
deptis still calleddept. 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.
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-Helpis 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:
grepis case-sensitive andSelect-Stringis not;>redirects in both shells;Rename-Itemwants 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.