Powershell's Equivalent to Linux's: Ls -Al

Powershell's equivalent to Linux's: ls -al

The ls Unix utility's options you're using:

  • -a option includes hidden items, which on Unix-like platforms are file-system items whose name starts with .

  • -l requests the so-called long format, which produces tabular output that includes the file-system items' mode, user and group ownership, the last-write timestamp, the item size, and its name.

The PowerShell equivalent is:

Get-ChildItem -Force
  • Get-ChildItem's -Force switch includes hidden items in the output - although, unlike with ls, the . and .. entries representing the target directory itself and its parent directory are not included (which makes it the equivalent of the more useful -A ls option).

  • The equivalent of long format formatting is used by default; if, conversely, you're interested in file names (relative paths) only, use the -Name switch.

  • Note: By default, Get-ChildItem targets the current location (directory); to specify an input path explicitly, use either the -Path parameter - for wildcard patterns - or the -LiteralPath parameter - for literal (verbatim) paths. The first positional argument (one not prefixed by a parameter names) implicitly binds to -Path; e.g., the following command targets the current user's home directory:

    Get-ChildItem -Force -LiteralPath $HOME
    • See this answer for more information.

See the bottom section for shortening this command and defining a convenience "alias" (function).


There's one fundamental difference between ls and Get-ChildItem, however:

  • ls outputs formatted text, and for that reason parsing its output is generally discouraged.

  • In PowerShell, formatting is separated from data and it is objects, not strings that are output.

    • That is, irrespective of the rich display formatting that Get-ChildItem output presents in the terminal, its actual output are objects of type System.IO.FileInfo and System.IO.DirectoryInfo, which can safely be used for further programmatic processing if captured in a variable, sent to other PowerShell comments through a pipeline, or used in an expression.
  • For instance, expression (Get-ChildItem -Force).FullName outputs the full paths of all items in the current directory.


For interactive convenience (you shouldn't do that in scripts), you can use built-in aliases and unambiguous parameter-name prefixes to shorten the command:

gci -fo

gci is built-in alias for Get-ChildItem, and its name follows PowerShell's naming conventions, where each so-called approved verb also has an approved 1-2 letter alias form; running Get-Verb Get reveals that the approved Get verb's alias form is g; while the noun part isn't formally regulated, remembering that ci stands for ChildItem should be easy.

-fo is the shortest parameter-name prefix that unambiguously refers to the -Force switch (just -f alone could also refer to -Filter[1])

  • Note: Some parameters themselves have actual aliases, such as -h for -Hidden or -ad for -Directory, but -Force does not.
  • Unlike unambiguous parameter-name prefixes, which can become ambiguous over time if new parameters are added to a command, parameter aliases are safe to use in scripts, although for readability the full names are preferable.

To see all aliases defined for a given command (Get-ChildItem in this example):

PS> Get-Alias -Definition Get-ChildItem

CommandType Name Version Source
----------- ---- ------- ------
Alias dir -> Get-ChildItem
Alias gci -> Get-ChildItem

To limit output to built-in aliases, i.e. to exclude aliases defined by other modules or $PROFILE scripts, run pwsh -noprofile { Get-Alias -Definition Get-ChildItem } (in Windows PowerShell, use powershell instead of pwsh.

  • The above shows the output on macOS and Linux.
  • On Windows you will see that ls is another built-in alias.
    • This is a legacy alias from the time PowerShell was a Windows-only shell, and is best avoided:

      • In general, aliases take precedence over external programs with the same name, and it isn't a good idea to shadow (override) a platform's standard command-line utilities; while that doesn't apply to alias ls on Windows, it does in other cases, namely where (shadows where.exe) and sc (Windows PowerShell-only, shadows sc.exe)

      • Specifically, given that the real ls Unix utility and Get-ChildItem have such vastly different syntax (and behavior), exposing the latter as ls is likely to cause confusion.

Therefore, it is advisable to stick to those aliases that are abbreviated forms of the PowerShell command names, such as gci for Get-ChildItem, and gc for Get-Content. While that doesn't initially help with transitioning from familiar names such as ls / dir and cat, the fact that PowerShell cmdlet names as well as their abbreviated aliases are systematic and convention-based makes it easier to memorize them going forward.

Defining a convenience "alias" with preset arguments, using a function:

POSIX-compatible shells such as bash allow you to define aliases with preset arguments, such as alias ll='ls -al'

By contrast, aliases in PowerShell are mere name mappings and you need to declare a function instead (which you can add to your $PROFILE file for availability in future session):

# Equivalent of bash alias `alias ll='ls -al'`
function ll { ls -al @args }

Or, an analogous gcih function (h denoting hidden) based on Get-ChildItem:

function gcih { Get-ChildItem -Force @args }

See this answer for more information about aliases vs. functions in PowerShell, including how to create more sophisticated wrapper functions.


[1] Conceptually, it could also refer to the -File parameter, but technically the latter is a dynamic parameter, specific to PowerShell's file-system provider, and is therefore not being considered during the ambiguity check.

ls' is not recognized as an internal or external command, operable program or batch file

I'm fairly certain that the ls command is for Linux, not Windows (I'm assuming you're using Windows as you referred to cmd, which is the command line for the Windows OS).

You should use dir instead, which is the Windows equivalent of ls.

Edit (since this post seems to be getting so many views :) ):

You can't use ls on cmd as it's not shipped with Windows, but you can use it on other terminal programs (such as GitBash). Note, ls might work on some FTP servers if the servers are linux based and the FTP is being used from cmd.

dir on Windows is similar to ls. To find out the various options available, just do dir/?.

If you really want to use ls, you could install 3rd party tools to allow you to run unix commands on Windows. Such a program is Microsoft Windows Subsystem for Linux (link to docs).

How to list files in windows using command prompt (cmd). I've tried using ' ls ' as in Linux but it shows an error?

Use the command dir to list all the directories and files in a directory; ls is a unix command.

Is there a way to create an alias to a cmdlet in a way that it only runs if arguments are passed to the alias?

You can't do it with an alias, because PowerShell aliases can only refer to another command name or path, and can therefore neither include arguments nor custom logic.

Therefore you do need a function, but it can be a short and simple one:

function which { if ($args.count) { Get-Command @args } else { Throw "Missing command name." } }

Note that while passing -? for showing Get-Command's help does work, tab completion of arguments does not.

In order to get tab completion as well, you'll need to write a wrapper (proxy) function or at least replicate Get-Command's parameter declarations - which then does make the function definition sizable.

If the concern is just the size of the $PROFILE file itself, you can write a proxy script instead - which.ps1 - which you can invoke with just which as well, assuming you place it in one of the directories listed in $env:Path[1]; see next section.



Defining a wrapper (proxy) script or function:

Defining a wrapper (proxy) function or script is a nontrivial undertaking, but allows you to implement a robust wrapper that supports tab completion and even forwarding to the original command's help.

Note:

  • Bug alert: As zett42 points out, as of PowerShell [Core] 7.1, System.Management.Automation.ProxyCommand.Create neglects to include dynamic parameters if the target command is an (advanced) function or script; however, compiled cmdlets are not affected; see GitHub issue #4792 and this answer for a workaround.

  • For simplicity, the following creates a wrapper script, which.ps1 , and saves it in the current directory. As stated, if you place it in one of the directories listed in $env:PATH, you'll be able to invoke it as just which.

  • The code below can easily be adapted to create a wrapper function instead: simply take the contents of the $wrapperCmdSource variable below and enclose it in function which { ... }.

  • As of PowerShell Core 7.0.0-preview.5, there are some problems with the auto-generated code, which may or may not affect you; they will be fixed at some point; to learn more and to learn how to manually correct them, see GitHub issue #10863.

# Create the wrapper scaffolding as source code (outputs a single [string])
$wrapperCmdSource =
[System.Management.Automation.ProxyCommand]::Create((Get-Command Get-Command))

# Write the auto-generated source code to a script file
$wrapperCmdSource > which.ps1

Note:

  • Even though System.Management.Automation.ProxyCommand.Create requires a System.Management.Automation.CommandMetadata instance to identify the target command, the System.Management.Automation.CommandInfo instances output by Get-Command can be used as-is.

  • Re comment-based help: By default, the proxy function simply forwards to the original cmdlet's help; however, you can optionally pass a string to serve as the comment-based help as the 2nd argument.

    • By using [System.Management.Automation.ProxyCommand]::GetHelpComments() in combination with output from Get-Help, you could start with a copy of the original command's help and modify it:
      [System.Management.Automation.ProxyCommand]::GetHelpComments((Get-Help Get-Command))

You now have a fully functional which.ps1 wrapper script that behaves like Get-Command itself.

You can invoke it as follows:

./which    # Same as: Get-Command; tab completion of parameters supported.
./which -? # Shows Get-Command's help.

You can now edit the script file to perform the desired customization.

Note: The auto-generated source code contains a lot of boilerplate code; however, typically only one or two places need tweaking to implement the custom functionality.

Specifically, place the following command as the first statement inside the begin { ... } block:

if (-not $MyInvocation.ExpectingInput -and -not ($Name -or $CommandType -or $Module -or $FullyQualifiedModule)) {
Throw "Missing command name or filter."
}

This causes the script to throw an error if the caller didn't provide some way of targeting a specific command or group of commands, either by direct argument or via the pipeline.

If you invoke the modified script without arguments now, you should see the desired error:

PS> ./which.ps1
Missing command name or filter.
...

Other common types of customizations are:

  • Removing parameters from the wrapper, by simply removing the parameter declaration.

  • Adding additional parameters to the invocation of the wrapped command, by modifying the following line in the begin block:

      # Add parameters, as needed.
    $scriptCmd = { & $wrappedCmd @PSBoundParameters }
  • Preprocessing pipeline input before passing it to the wrapped command, by customizing the process block and replacing $_ with your preprocessed input in the following line:

      # Replace $_ with a preprocessed version of it, as needed.
    $steppablePipeline.Process($_)

For an example of a complete implementation of a proxy function, see this answer.


[1] Caveat for Linux users: since the Linux file-system is case is case-sensitive, invocation of your script won't work case-insensitively, the way commands normally work in PowerShell. E.g., if your script file name is Get-Foo.ps1, only Get-Foo - using the exact same case - will work, not also get-foo, for instance.

How to pass arguments to Unix-like commands (via MinGW) in PowerShell

ls is an alias in Powershell for the get-childitem command. If you want to run an external command called ls you will need to force Powershell to ignore its own ls command.

You could try running ls.exe, or specify the path to the MinGW command, or undefine the Powershell alias. Or learn to use the options for Powershell's own ls command instead.

The nearest Powershell equivalent to ls -al would be ls -Force This will display all hidden and system files and Powershell's default output for ls looks somewhat like the ls -l format anyway.

You can check which command will be run using Powershell's get-command which does a similar job to which (or use gcm as shorthand for less typing:

PS C:\Users\IEUser> get-command ls.exe

CommandType Name Version Source
----------- ---- ------- ------
Application ls.exe 0.0.0.0 C:\Program Files\OpenSSH\bin\ls.exe

PS C:\Users\IEUser> get-command ls

CommandType Name Version Source
----------- ---- ------- ------
Alias ls -> Get-ChildItem

PS C:\Users\IEUser> gcm ls

CommandType Name Version Source
----------- ---- ------- ------
Alias ls -> Get-ChildItem

PS C:\Users\IEUser> gcm ls.exe

CommandType Name Version Source
----------- ---- ------- ------
Application ls.exe 0.0.0.0 C:\Program Files\OpenSSH\bin\ls.exe

and if you don't want to learn a new command:

PS C:\Users\IEUser> set-alias which gcm
PS C:\Users\IEUser> which ls

CommandType Name Version Source
----------- ---- ------- ------
Alias ls -> Get-ChildItem

Why does an error keep popping up when ls -a is used?

That tutorial is meant for POSIXy systems such as Linux, and you're using Windows.

Windows' PowerShell happens to have an alias ls for listing items in a directory, but it does not directly support -a (which the POSIX ls command does support).



Related Topics



Leave a reply



Submit