Demonstrate uname Options
Personally, I never made a habit of using the uname command on Linux.
uname is a basic utility which is primarily used to print the kernel version. But, there are other options available.
I typically use the -a option which prints everything.
But, today, I sat down and tried every option to see what they all did. Note that uname with no supplied option implies -s.
To make displaying every option easier, I wrote a PowerShell one-liner that demonstrates every uname option.
You can find an explanation of each part in the sections below.
As you can see, if I want just the kernel version then I can use uname -r
@('a','s','n','r','v','m','p','i','o') | foreach-object { "$_`n$(uname -$_)`n" } a Linux john.local 6.10.5-1-default #1 SMP PREEMPT_DYNAMIC Fri Aug 16 11:15:41 UTC 2024 (30fd964) x86_64 x86_64 x86_64 GNU/Linux s Linux n john.local r 6.10.5-1-default v #1 SMP PREEMPT_DYNAMIC Fri Aug 16 11:15:41 UTC 2024 (30fd964) m x86_64 p x86_64 i x86_64 o GNU/Linux
uname
Let's start with the uname manual page.
man uname
Once the manual page loads, you will see the command options in the description section. This gives us the letters that we will use later as inputs. For example, -a or -s.
UNAME(1) User Commands UNAME(1) NAME uname - print system information SYNOPSIS uname [OPTION]... DESCRIPTION Print certain system information. With no OPTION, same as -s. -a, --all print all information, in the following order, except omit -p and -i if unknown: -s, --kernel-name print the kernel name -n, --nodename print the network node hostname -r, --kernel-release print the kernel release -v, --kernel-version print the kernel version -m, --machine print the machine hardware name -p, --processor print the processor type (non-portable) -i, --hardware-platform print the hardware platform (non-portable) -o, --operating-system print the operating system --help display this help and exit --version output version information and exit
Array
From a programmer's perspective, the letters change for each uname option listed above: a, s, n, r, ... So, I'll want to collect those letters and use them later.
Using the PowerShell array operator @( ) allows us to create an array of single-character strings. For example, 'a' and 's' are full string objects in PowerShell instead of chars like in other programming languages.
Commas separate the elements of the array.
@('a','s','n','r','v','m','p','i','o')
Pipeline
PowerShell typically processes information in a pipeline. Along with objects, pipelines are a central feature of PowerShell and are regularly used.
Conceptually, pipelines connect the output from one command to the input of another command.
It is also important to understand that, in PowerShell, collections like our array are passed down the pipeline one array element at a time. So, two things will happen to the next command in the pipeline. One, the next command in the pipeline will be invoked once for each value passing through the pipeline. And, two, the command will receive one element of data as input during each invocation. So, in our case, the next command in the pipeline will receive one letter with each invocation.
Sending collections down the pipeline one element at a time is a useful default behavior. And this lets pipelines take the general form of:
- Placing a collection of data at the beginning of the pipeline.
- And, using subsequent pipeline commands to process or filter individual elements of that collection.
That's what we will do in our example today.
Since PowerShell is object-oriented, even data--like our array--have implicit outputs. What that means is, simply putting the array at the beginning of a pipeline will pass the individual array elements (letters in our case) to the next command in the pipeline.
So a simple solution to our problem would be to feed the letters in the array into a command which used each letter as a uname option. That's the basic approach I'll follow here.
To tell PowerShell to link the array with a following command as a pipeline, we use the pipe symbol or vertical bar | On US keyboards, you typically hold Shift and press Backslash together to produce a pipe symbol.
In our example, the pipe will connect the implicit output of the array--the letters--and the input to our command.
@('a','s','n','r','v','m','p','i','o') | # some command
Also, to refer to each input in later pipeline commands, we will use the $_ automatic variable. $_ represents the current object traveling down the pipeline. For example, $_ might represent the letter 'a' when pipeline command is invoked for the first time. This gives you a convenient way to refer to input from the pipeline inside your command. Just type dollar sign and underscore to refer to the automatic variable.
@('a','s','n','r','v','m','p','i','o') | ForEach-Object { "The current letter in the pipeline is $_" } The current letter in the pipeline is a The current letter in the pipeline is s The current letter in the pipeline is n The current letter in the pipeline is r The current letter in the pipeline is v The current letter in the pipeline is m The current letter in the pipeline is p The current letter in the pipeline is i The current letter in the pipeline is o
ForEach-Object
ForEach-Object is a PowerShell cmdlet (pronounced "command-let"). cmdlets are PowerShell commands.
ForEach-Object allows you to add custom code to a pipeline. Inside a ForEach-Object code block, you can write any valid PowerShell code. Code blocks consist of PowerShell code between matching curly braces { }
For example, below is how our pipeline would look with ForEach-Object added to the end.
Note: cmdlet names are not case-sensitive.
@('a','s','n','r','v','m','p','i','o') | foreach-object { <# custom code #> }
Output String
Let's focus on getting our custom code to work for one letter of input. And, let's start with something simple like a string. We'll start with just one of the uname options.
We create a PowerShell string by placing double-quotes before and after the text.
"a"
Now, inside our string, let's pretend to invoke uname.
"uname -a"
If we were to invoke that command for real then we would receive the output of the command. That's normal. But, in our case, it might be confusing to see only the output of commands without seeing the commands themselves.
If we want to see the commands then we'll have to add them ourselves to the output. Or, as I've done, I will just output the letter so that you can tell which uname option was used.
So, let's add a placeholder to our mock-up. And let that placeholder represent the option used in the command. So, if I use the -a option then I should see both the option 'a', and the output of the command.
For now, let's use the following as our string.
"(the option a) (the output from uname -a)"
One thing we can do with our string is put the option and command output on different lines.
Programming languages typically have an escape sequence that allows you to insert a newline into string output. PowerShell uses the escape sequence `n where ` is the backtick character and n is the literal 'n' character. Backtick can be typed by pressing the tilde ~ key which is to the left of the 1 key.
Note: For clarity, the backtick ` key produces backtick by default. And holding Shift and pressing backtick produces tilde ~ instead.
We can use `n to separate the option from the output. And, we can add a newline to the end of the string to add a buffer between outputs.
"(the option a) `n (the output from uname -a) `n"
Let's run this and see how it behaves with our pipeline.
@('a','s','n','r','v','m','p','i','o') | foreach-object { "(the option a) `n (the output from uname -a) `n" } (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a) (the option a) (the output from uname -a)
This output is basically correct.
- There are nine outputs: one for each input.
- The text we entered is showing.
- The lines are broken up and spaced with the newline `n escape sequences we used.
Also, notice that I just have a simple string as the only object inside the code block { }. This works because ForEach-Object returns the string object. And, PowerShell implicitly prints the string without an explicit command to do so.
Continuing, let's try using the $_ automatic variable to replace our letter 'a' with the actual input.
@('a','s','n','r','v','m','p','i','o') | foreach-object { "$_ `n uname -$_ `n" } a uname -a s uname -s n uname -n r uname -r v uname -v m uname -m p uname -p i uname -i o uname -o
I can see that the inputs are now being formatted by our string and output by the pipeline.
Subexpression Operator
At this point, the output string looks fine. And we just need to solve the problem of actually running the uname command with an option.
While ForEach-Object can run code directly, I've chosen to use a simple string as the only code within the code block.
So, let's continue with that string. And, let's try to run some code inside the string.
We can run code inside of a string with the subexpression operator $( ) For example, "$(uname -a)" runs the uname -a command.
And, if we keep the $_ automatic variable then we'll have a command that automatically updates for each letter in our array.
Note: Below, I've removed some spaces to match my original one-liner. If you prefer the spacing from the previous example then feel free to add the spaces back in.
This is the final command as shown at the top of the gemlog.
@('a','s','n','r','v','m','p','i','o') | foreach-object { "$_`n$(uname -$_)`n" } a Linux john.local 6.10.5-1-default #1 SMP PREEMPT_DYNAMIC Fri Aug 16 11:15:41 UTC 2024 (30fd964) x86_64 x86_64 x86_64 GNU/Linux s Linux n john.local r 6.10.5-1-default v #1 SMP PREEMPT_DYNAMIC Fri Aug 16 11:15:41 UTC 2024 (30fd964) m x86_64 p x86_64 i x86_64 o GNU/Linux
As you can now see, each option is provided by the array to the pipeline. And, ForEach-Object lets us run code against each value flowing down the pipeline: in this case, each letter.
The string in the code block outputs the uname option, uses a subexpression $( ) operator to run a command, and uses the `n escape sequence to put each output on its own line.
References
Linux man Command | Baeldung on Linux
{ } about_Script_Blocks | Microsoft
<# #> Comments | Language Specification | Microsoft
" " Strings | about_Quoting_Rules | Microsoft
`n about_Special_Characters | Microsoft
$( ) Subexpression Operator | about_Operators | Microsoft
Created: Tuesday, September 3, 2024
Updated: Tuesday, September 3, 2024
/gemlog/