##### A Unix Person's Guide to PowerShell

Principal author: Matt Penny

This e-book is intended as a ‘Quick Start’ guide to PowerShell for people who already know Bash or one of the other Unix shells.

The book has 3 elements:

• an introductory chapter which covers some PowerShell concepts
• a summary list of PowerShell equivalents of Unix commands in one e-book chapter
• a detailed discussion of Powershell equivalents of Unix commands, organised in the alphabetical order of the unix command

This guide is released under the Creative Commons Attribution-NoDerivs 3.0 Unported License. The authors encourage you to redistribute this file as widely as possible, but ask that you do not modify the document.

Was this book helpful? The author(s) kindly ask(s) that you make a tax-deductible (in the US; check your laws if you live elsewhere) donation of any amount to The DevOps Collective to support their ongoing work.

Check for Updates! Our ebooks are often updated with new and corrected content. We make them available in three ways:

• Our main, authoritative GitHub organization, with a repo for each book. Visit https://github.com/devops-collective-inc/
• Our GitBook page, where you can browse books online, or download as PDF, EPUB, or MOBI. Using the online reader, you can link to specific chapters. Visit https://www.gitbook.com/@devopscollective
• On LeanPub, where you can download as PDF, EPUB, or MOBI (login required), and “purchase” the books to make a donation to DevOps Collective. You can also choose to be notified of updates. Visit https://leanpub.com/u/devopscollective

GitBook and LeanPub have slightly different PDF formatting output, so you can choose the one you prefer. LeanPub can also notify you when we push updates. Our main GitHub repo is authoritative; repositories on other sites are usually just mirrors used for the publishing process. GitBook will usually contain our latest version, including not-yet-finished bits; LeanPub always contains the most recent “public release” of any book.

## Introduction to PowerShell for Unix people

The point of this section is to outline a few areas which I think *nix people should pay particular attention to when learning Powershell.

### Resources for learning PowerShell

A full introduction to PowerShell is beyond the scope of this e-book. My recommendations for an end-to-end view of PowerShell are:

### unix-like aliases

PowerShell is a friendly environment for Unix people to work in. Many of the concepts are similar, and the PowerShell team have built in a number of Powershell aliases that look like unix commands. So, you can, for example type:

….and get this:

These can be quite useful when you’re switching between shells, although I found that it can be irritating when the ‘muscle-memory’ kicks in and you find yourself typing ls -ltr in PowerShell and get an error.

### the pipeline

The PowerShell pipeline is much the same as the Bash shell pipeline. The output of one command is piped to another one with the ‘|’ symbol.

The big difference between piping in the two shells is that in the unix shells you are piping text, whereas in PowerShell you are piping objects.

This sounds like it’s going to be a big deal, but it’s not really.

In practice, if you wanted to get a list of process names, in bash you might do this:

…whereas In PowerShell you would do this:

In Bash you are working with characters, or tab-delimited fields. In PowerShell you work with field names, which are known as ‘properties’.

You can determine the properties of a Powershell object with the command get-member

### get-help, get-command, get-member

##### get-member

When you run a PowerShell command, such as get-history only a subset of the get-history output is returned to the screen.

In the case of get-history, by default two properties are shown - ‘Id’ and ‘Commandline’…

…but get-history has 4 other properties which you might or might not be interested in:

The disparity between what is shown and what is available is even greater for more complex entities like ‘process’. By default, on my screen, get-process shows 8 columns, but there are actually over 50 properties (as well as 20 or so methods) available.

The full range of what you can return from a PowerShell command is given by the get-member command[2].

To run get-member, you pipe the output of the command you’re interested in to it, for example:

….or, more typically:

get-member is one of the ‘trinity’ of ‘help’-ful commands:

• get-member
• get-help
• get-command
##### get-help

get-help is similar to the Unix man[3].

So if you type get-help get-process, you’ll get this:

There are a couple of wrinkles which actually make the PowerShell ‘help’ even more help-ful.

• you get basic help by typing get-help, more help by typing get-help -full and…probably the best bit as far as I’m concerned…you can cut to the chase by typing get-help -examples
• there are lots of ‘about_’ pages. These cover concepts, new features (in for example about_Windows_Powershell_5.0) and subjects which dont just relate to one particular command. You can see a full list of the ‘about’ topics by typing get-help about
• get-help works like man -k or apropos. If you’re not sure of the command you want to see help on, just type help process and you’ll see a list of all the help topics that talk about processes. If there was only one it would just show you that topic
• Comment-based help. When you write your own commands you can (and should!) use the comment-based help functionality. You follow a loose template for writing a comment header block, and then this becomes part of the get-help subsystem. It’s good.
##### get-command

If you don’t want to go through the help system, and you’re not sure what command you need, you can use get-command.

I use this most often with wild-cards either to explore what’s available or to check on spelling.

For example, I tend to need to look up the spelling of ConvertTo-Csv on a fairly regular basis. PowerShell commands have a very good, very intuitive naming convention of a verb followed by a noun (for example, get-process, invoke-webrequest), but I’m never quite sure where ‘to’ and ‘from’ go for the conversion commands.

To quickly look it up I can type:

get-command *csv*

… which returns:

### Functions

Typically PowerShell coding is done in the form of functions[4]. What you do to code and write a function is this:

Create a function in a plain text .ps1 file[5]

…then source the function when they need it

…then run it

Often people autoload their functions in their $profile or other startup script, as follows: ### Footnotes [1] If you wanted the equivalent of ls -ltr you would use gci | sort lastwritetime. ‘gci’ is an alias for ‘get-childitem’, ‘sort’ is an alias for ‘sort-object’. [2] Another way of returning all of the properties of an object is to use ‘select *‘…so in this case you could type get-process | select * [3] There is actually a built-in alias man which tranlates to get-help, so you can just type man if you’re pining for Unix. [4] See the following for more detail on writing functions rather than scripts: http://blogs.technet.com/b/heyscriptingguy/archive/2011/06/26/don-t-write-scripts-write-powershell-functions.aspx [5] I’m using ‘gvim’ here, but notepad would work just as well. PowerShell has a free ‘scripting environment’ called PowerShell ISE, but you don’t have to use it if you dont want to. ## commands summary | Unix | Powershell | | —–|————| | alias (set aliases) | set-alias | | alias (show aliases) | get-alias | | apropos | get-help | basename | dir | select name | cal | See commands detail | | cd | cd | | clear | clear-host | | date | get-date | | date -s | set-date | | df -k | Get-WMIObject Win32_LogicalDisk | ft -a | | diff | Compare-Object -ReferenceObject (Get-Content file1) -DifferenceObject (Get-Content file2) | | dirname | dir | select directory | | du | See commands detail | | echo | write-output | | echo -n | write-host -nonewline | | | egrep -i sql | | where {[Regex]::Ismatch($_.name.tolower(), “sql”) } | | egrep -i | select-string | | egrep | select-string -casesensitive | | egrep -v | select-string -notmatch | | env | Get-ChildItem Env: | fl or get-variable | | errpt | get-eventlog | | export PS1=”$“ | function prompt {“$ “ } | | find | dir whatever -recurse | | for (start, stop, step) | for ($i = 1;$i -le 5; $i++) {whatever} | | head | gc file.txt | select-object -first 10 | | history | get-history | | history | egrep -i ls | history | select commandline | where commandline -like ‘ls’ | fl | | hostname | hostname | | if-then-else | if ( condition ) { do-this } elseif { do-that } else {do-theother} | | if [ -f “$FileName” ] | if (test-path $FileName) | | kill | stop-process | | less | more| | locate | no equivalent but see link | | ls | get-childitem OR gci OR dir OR ls | | ls -a | ls -force | | lsusb | gwmi Win32_USBControllerDevice | | mailx | send-mailmessage | | man | get-help | | more | more| | mv | rename-item | | pg | more| | ps -ef | get-process | | ps -ef | grep oracle | get-process oracle | | pwd | get-location | | read | read-host | | rm | remove-item | | script | start-transcript | | sleep | start-sleep | | sort | sort-object | | sort -uniq | get-unique | | tail | gc file.txt | select-object -last 10 | | tail -f | gc -tail 10 -wait file.txt | | time | measure-command | | touch - create an empty file | set-content -Path ./file.txt -Value$null | | touch - update the modified date | set-itemproperty -path ./file.txt -name LastWriteTime -value $(get-date) | | wc -l | gc ./file.txt | measure-object | select count | | whoami | [Security.Principal.WindowsIdentity]::GetCurrent() | select name | | whence or type | No direct equivalent, but see link | | unalias | remove-item -path alias:aliasname | | uname -m | Get-WmiObject -Class Win32_ComputerSystem | select manufacturer, model | | uptime | get-wmiobject -class win32_operatingsystem | select LastBootUpTime | | \ (line continuation) |  (a backtick) | ## commands detail - a ### alias (list all the aliases) The Powershell equivalent of typing alias at the bash prompt is: ### alias (set an alias) At it’s simplest, the powershell equivalent of the unix ‘alias’ when it’s used to set an alias is ‘set-alias’ However, there’s a slight wrinkle…. In unix, you can do this If you try doing this in Powershell, it doesn’t work so well. If you do this: …then you get this error: A way around this is to create a function instead: You could then create an alias for the function: ### apropos apropos is one of my favourite bash commands, not so much for what it does…but because I like the word ‘apropos’. I’m not sure it exists on all flavours of *nix, but in bash apropos returns a list of all the man pages which have something to do with what you’re searching for. If apropos isn’t implemented on your system you can use man -k instead. Anyway on bash, if you type: …then you get: The Powershell equivalent of apropos or man -k is simply get-help This is quite a nice feature of PowerShell compared to Bash. If get-help in Powershell shell scores a ‘direct hit’ (i.e. you type something like get-help debug-process) it will show you the help for that particular function. If you type something more vague, it will show you a list of all the help pages you might be interested in. By contrast if you typed man process at the Bash prompt, you’d just get ## commands detail - b ### basename A rough PowerShell equivalent for the unix basename is: This depends on the file actually existing, whereas basename doesn’t care. A more precise (but perhaps less concise) alternative[1] is: Notes [1] I found [System.IO.Path]::GetFileName after reading Power Tips of the Day - Useful Path Manipulations Shortcuts, which has some other useful commands ## commands detail - c ### cal There’s no one-liner equivalent for the Linux cal, but there’s a useful script, with much of the cal functionality here : http://www.vistax64.com/powershell/17834-unix-cal-command.html ### cd The PowerShell equivalent of cd is: …although there is a builtin PowerShell alias cd which points at set-location #### cd ~ cd ~ moves you to your home folder in both unix and Powershell. ### clear The unix clear command clears your screen. The Powershell equivalent to the unix clear is PowerShell also has built-in alias clear for clear-host. However, it’s possibly worth noting that the behaviour of the two commands is slightly different between the two environments. In my Linux environment, running putty, clear gives you a blank screen by effectively scrolling everything up, which means you can scroll it all back down. The Powershell Clear-host on the other hand seems to wipe the previous output (actually in the same way that cmd’s cls command does….). This could be quite a significant difference, depending on what you want to clear and why! ### cp The Posh version of cp is The following are built-in aliases for copy-item: ### cp -R To recursively copy: ## commands detail - d ### date The Powershell equivalent of the Unix date is The Powershell equivalent of the Unix date -s is I was anticipating doing a fairly tedious exercise of going through all the Unix date formats and then working out the Powershell equivalent, but discovered the Powershell Team has effectively done all this for me. There is a Powershell option -UFormat which stands for ‘unix format’. So the Powershell: is the same as the *nix This is handy…but I have found the odd difference. I tried this for a demo: Unix: Powershell: I presume the discrepancy in the week of the year is to do with when the week turns - as you can see I ran the command on a Monday. Some systems have the turn of the week being Monday, others have it on Sunday. I don’t know why %Z outputs different things….and I can’t help feeling I’m being churlish pointing this out. The -UFormat option is a really nice thing to have. ### df -k A quick and dirty Powershell equivalent to ‘df -k’ is A slightly prettier version is this function: ….then you can just do: ….and get ### dirname A good PowerShell equivalent to the unix dirname is However, this isn’t a direct equivalent. Here, I’m telling Powershell to look at an actual file and then return that file’s directory. The file has to exist. The unix ‘dirname’ doesn’t care whether the file you specify exists or not. If you type in dirname /tmp/double_winners/chelsea.doc on any Unix server it will return /tmp/double_winners, I think. dirname is essentially a string-manipulation command. A more precise Powershell equivalent to the unix ‘dirname’ is this ….but it’s not as easy to type, and 9 times out of 10 I do want to get the folder for an existing file rather than an imaginary one. ### du While I think there are implementations of du in PowerShell, personally my recommendation would be to download Mark Russinovich’s ‘du’ tool, which is here: http://technet.microsoft.com/en-us/sysinternals/bb896651.aspx This is part of the Microsoft’s ‘sysinternals’ suite. ## commands detail - e ### echo echo is an alias in PowerShell. As you would expect it’s an alias for the closest equivalent to the Linux echo: • write-output You use it as follows: As well as write-output there are a couple of options for use in Powershell scripts and functions: • write-debug • write-verbose Whether these produce any output is controlled by commandline or environment flags. ### echo -n In bash, echo -n echoes back the string without printing a newline, so if you do this: you get: ….with your cursor ending up on the same line as the output, just after the dollar prompt Powershell has an exact equivalent of ‘echo -n’. If you type: ….then you get this: Note that -nonewline doesn’t ‘work’ if you’re in the ISE. ### egrep The best PowerShell equivalent to egrep or grep is select-string: A nice feature of select-string which isn’t available in grep is the -context option. The -context switch allows you to see a specified number of lines either side of the matching one. I think this is similar to SEARCH /WINDOW option in DCL. ### egrep -i Powershell is case-insensitive by default, so: …would return: If you want to do a case sensitive search, then you can use: ### egrep -v The Powershell equivalent to the -v option would be -notmatch ### egrep ‘this|that’ To search for more than one string within a file in bash, you use the syntax: This will return lines which contain either ‘blue’ or ‘stamford’. The PowerShell equivalent is to seperate the two strings with a comma, so: …returns: ### | egrep -i sql This is an interesting one, in that it points up a conceptual difference between PowerShell and Bash. In bash, if you want to pipe into a grep, you would do this: This would show you all the processes which include the string ‘sql’ somewhere in the line returned by ps. The egrep is searching across the whole line. If the username is ‘mr_sql’ then a line would be returned, and if the process is ‘sqlplus’ than a line would also be returned. To do something similar in PowerShell you would do something more specific So the string ‘sql’ has to match the contents of the property processname. As it happens, get-process by default only returns one text field, so in this case it’s relatively academic, but hopefully it illustrates the point. ### env The Linux ‘env’ shows all the environment variables. In PowerShell there are two set of environment variables: - windows-level variables and - Powershell-level variable Windows-level variables are given by: PowerShell-level variables are given by: ### errpt I think errpt is possibly just an AIX thing (the linux equivalent is, I think, looking at /var/log/message). It shows system error and log messages. The PowerShell equivalent would be to look at the Windows eventlog, as follows The lognames that I typically look at are ‘system’, ‘application’ or ‘security’. ### export PS1=”$ “

In bash the following changes the prompt when you are at the command line

The Powershell equivalent to this is:

I found this on Richard Siddaway’s blog: http://msmvps.com/blogs/richardsiddaway/archive/2013/07/21/fun-with-prompts.aspx

## commands detail - f

### find

The bash find command has loads of functionality - I could possibly devote many pages to Powershell equivalents of the various options, but at it’s simplest the bash find does this:

The simplest Powershell equivalent of the bash find is simply to stick a -recurse on the end of a dir command

If you want Powersehll to give you output that looks more like the Unix find then you can pipe into | select fullname

### for

#### for loop - start, stop, step

The equivalent of this bash:

…is

#### for loop - foreach item in a list

For the Bash

the equivalent Powershell is:

#### for loop - for each word in a string

For the bash:

…the equivalent Powershell is:

Bash:

Posh:

or:

Bash:

Posh:

## commands detail - g

Not got any commands beginning with ‘g’ yet.

## commands detail - h

The PowerShell equivalent of the *nix head is:

### history

The Powershell equivalent of history is:

There is a built in alias history

It’s worth noting that history doesn’t persist across PowerShell sessions, although if you search online there are a couple of published techniques for making it persistent.

It’s also perhaps worth noting that Powershell gives you a couple of extra bits of information, if you want them:

### history | egrep -i ls

There is no direct equivalent of the shell functionality you get with set -o vi sadly. You can up- and down- arrow by default, but if you want to search through your history then you need to do something like this

### hostname

There is a windows hostname which does much the same thing as the Unix hostname, but it’s not Powershell. It’s a standard-ish Windows executable that on my machine lives in c:\windows\system32

You can get the server name through PowerShell like this:

## commands detail - i

### if-then-else

The bash if-then-elif-else as per:

…could be rendered in PowerShell as:

#### ps -ejH (print a process tree)

There is no PowerShell equivalent to the Unix ps -eJH, because as I understand it Windows processes aren’t part of a process tree.

### pwd

To show your current location in Powershell:

…or there are aliases gl and pwd.

There is also a built-in variable

None as yet

## commands detail - r

In *nix:

In Powershell:

To not echo the input to screen, you would do

This echoes out an asterisk for each character input

## commands detail - s

### sleep

or

or just:

…will sleep for 3 seconds

### sort -u

The closest PowerShell equivalent to the unix sort -u is get-unique

Note: this only works as far I can see if you sort it first

Note 2: get-unique IS case sensitive

### sql

This isn’t really a Powershell equivalent of a unix command, but in case it’s useful, to call Sqlserver’s implementation of the sql command line from Powershell you can use invoke-sqlcmd

You need to have the sql module loaded for this to work, or be running the Powershell console from within SSMS

## commands detail - t

### tail

gc is an alias for get-command

### tee

The Powershell equivalent of the unix tee is tee-object….which, by default is aliased to tee

So you can do this:

…to both get a list of processes on your screen and get that output saved into the file in c:\temp

### time

The Powershell equivalent of the bash shell ‘time’ is ‘measure-command’.

So, in bash you would do this:

….and get all the egrep output, then

In Powershell, you would do this

…and get…

…you don’t get the ‘user CPU’ time and ‘system CPU’ time, but you do get the added bonus of seeing how long the command took rendered as a fraction of a day!

### touch - create an empty file

I found the set-content command at <a href=”http://superuser.com/questions/502374/equivalent-of-linux-touch-to-create-an-empty-file-with-powershell”>Super User</a>, the contributor being <a href=”http://superuser.com/users/23133/techie007”>user techie007</a>

### touch - update the modified date

I got this from a comment by <a href=”https://twitter.com/manung”>Manung Han</a> on the <a href=”http://blog.lab49.com/archives/249#comment-1076”>Lab49 Blog</a>. Doug Finke shares <a href=”http://blog.lab49.com/archives/249”>touch function</a> in a later comment on the same post that fully implements the linux command.

## commands detail - u

### uname

#### uname -s

uname -s in Unix, according to the man page, gives the ‘kernel-version’ of the OS. This is the ‘top-level version’ of the Unix that you’re on. Typical values are ‘Linux’, or ‘AIX’ or ‘HP-UX’. So, on my laptop, typing uname -s gives:

I’ve only used this when writing a Unix script which have to do slightly different things on different flavours of unix.

Obviously, there’s only one manufacturer for Windows software - Microsoft. So there’s no direct equivalent to uname -s. The closest equivalent on Powershell would I think be:

get-wmiobject -class win32_operatingsystem | select caption

This returns:

or

or

or

or

#### uname -n

According to the Linux help, uname -n does this:

So, typing uname -n gives

I haven’t found a neat equivalent for this in Powershell, but this works:

The output is:

#### uname -r

uname -r gives the kernel release in Unix. The output varies depending on the flavour of Unix - Wikipedia has a good list of examples

On my system uname -r gives:

The best Powershell equivalent would seem to be:

…which gives:

The 7601 is Microsoft’s build number.

#### uname -v

uname -v typically gives the date of the unix build. As far a I can think, there isn’t a Powershell equivalent

#### uname -m

To be honest, I’m not entirely sure what uname -m shows us on Unix. The wikipedia page for uname shows various outputs none of which are hugely useful.

Running uname -m on my server gives:

Is this a PowerShell equivalent?

### uptime

On most, but from memory possibly not all, flavours of *nix ‘uptime’ tells you how long the server has been up and running

A rough Powershell equivalent to show how long the server (or PC) has been running is:

….of course you can also do

…to get the bootup time for a remote server, or PC.

## commands detail - v

No commands beginning with ‘v’ so far.

## commands detail - w

### wc -l

to show the number of <i>non-blank</i> lines:

### whoami

This shows the user that you are logged on as:

### whence or type

There isn’t a close equivalent to the unix whence command, because within Powershell there isn’t a PATH variable for scripts. The environment’s PATH and PSMODULEPATH list the folders for windows executables and for Powershell modules.

get-command` shows the location of the windows executable, the name of the Powershell module or the translation of the alias, as follows:

None yet

None yet

None yet

To be completed

## Todo

While the first version of this e-book is being written this list will be largely mechanical stuff which needs to be done to get the e-book into a suitable state. Subsequently it will be more a list of unix stuff for which I/we stilll need to find or document a PowerShell equivalent.

### for future versions

• look at http://blogs.technet.com/b/josebda/archive/2015/04/18/windows-powershell-equivalents-for-common-networking-commands-ipconfig-ping-nslookup.aspx

test conditions (not entirely sure that’s the right unix terminology) - built test conditions like if file exists and is not a directory, if variable exists and is not null

pushd/popd

shutdown -r - restart-computer

more/less - remember it doesn’t work in ISE

find - the various options. -newer, -exec

uname uname options

crontab -l cp -r ls -R .profile

bg cp cut

env eval file find free (memory) fuser filename head

tee

/var/log/message write & (run in background) PS1 (line contunuation prompt) declare -F type Parameter passing cut -f 3 for (p127) while (p139) until case select p113, p136 String comparisons p118 File attribute operations p122 fileinfo Number comparisons p126 IFS (internal field separator) p127 PS3 getopts p145 let p145 arrays p160 here -documents p165 debugging stuff p221 -n (syntax check) -v -x

For the section on ‘ | egrep -i’ i.e. how to search for something within the pipeline, I’ve currently got instructions on how to use -like against a particular property. It would be good to have an alternative which did allow you to search across the whole output. Not very useful typically, but it would be nice to cover it off

export (variables)

my search history function

Mark L’s comments - would expect to see stuff like ‘if-then-else’ in the introductory pages - would be worth looking at the man pages for bash itself (and perhaps for cmd) - cover re-direction - ‘special variables’ - $HOME,$PROFILE

More detail on invoke-locate ?

Cover Get-Item as well as Get-ChildItem for ls

Convert from gwmi to get-ciminstance

More on mailx/send-mailmessage

Think about whether to expand any and all aliases to the full command name

More on mv?

Fill out detail on the ps process tree option. All unix processes being descendants of root, windows processes not necessarily being descendants of anything

More on more :). More isn’t an alias for out-host -paging

ps options - starting with those in the cygwin or bash help

ps -0 (get security info) ps -eo euser,ruser,suser,fuser,f,comm,label ps axZ ps -eM

….have been looking at the cim but not got anything much yet. http://powershell.com/cs/blogs/tips/archive/2009/12/17/get-process-owners.aspx has wmi

#### ps -p

rm options

rmdir

sort and sort -uniq - more detail on each

uptime - restore the ‘sos’ function etc….but work out what the approved verb would be for ‘show’

who am i - as opposed to whoami. I think it shows the user you originally logged on as

the non-alphabetical stuff: \ and backtick

$env | sort _=/bin/env CVS_RSH=ssh G_BROKEN_FILENAMES=1 HISTSIZE=1000 HOME=/home/matt HOSTNAME=whatever.co.uk INPUTRC=/etc/inputrc LANG=en_GB LESSOPEN=|/usr/bin/lesspipe.sh %s LOGNAME=matt LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;32:.cmd=00;32:.exe=00;32:.com=00;32:.btm=00;32:.bat=00;32:.sh=00;32:.csh=00;32:.tar=00;31:.tgz=00;31:.arj=00;31:.taz=00;31:.lzh=00;31:.zip=00;31:.z=00;31:.Z=00;31:.gz=00;31:.bz2=00;31:.bz=00;31:.tz=00;31:.rpm=00;31:.cpio=00;31:.jpg=00;35:.gif=00;35:.bmp=00;35:.xbm=00;35:.xpm=00;35:.png=00;35:.tif=00;35: MAIL=/var/spool/mail/matt PATH=/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/matt/bin PS1=$ PWD=/home/matt SHELL=/bin/bash SHLVL=1 SSH_TTY=/dev/pts/1 TERM=xterm