aws-cli icon indicating copy to clipboard operation
aws-cli copied to clipboard

Pager preference is not obeyed on Windows

Open jimbo8098 opened this issue 2 years ago • 2 comments

Describe the bug

The AWS_PAGER environment variable or cli_pager config file parameter is not obeyed specifically if you wish to disable pagination. It is obeyed if you set it to a paginator of your choice.

Expected Behavior

Per the AWS CLI documentation you can set the AWS_PAGER environment variable to be a blank string (i.e. not $null) or you can set the relevant option in config like so:

cli_pager=

Both of these would not result in paginated output.

Current Behavior

> $Env:AWS_PAGER=$null
> aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json
'more' is not recognized as an internal or external command,
operable program or batch file.
> $Env:AWS_PAGER="less"
> aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json
'less' is not recognized as an internal or external command,
operable program or batch file.
> $Env:AWS_PAGER=""
> aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json
'more' is not recognized as an internal or external command,
operable program or batch file.
> [System.Environment]::SetEnvironmentVariable("AWS_PAGER","")
> aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json
'more' is not recognized as an internal or external command,
operable program or batch file.
> [System.Environment]::SetEnvironmentVariable("AWS_PAGER","less")
> aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json
'less' is not recognized as an internal or external command,
operable program or batch file.
> [System.Environment]::SetEnvironmentVariable("AWS_PAGER",$null)
> aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json
'more' is not recognized as an internal or external command,
operable program or batch file.

Note that if I instead run the AWS CLI command with --no-cli-pager, like below, the command works as expected:

aws ec2 describe-instances --filters "Name=tag:Name,Values=Workstation" --query Reservations[].Instances[] --output json --no-cli-pager

Reproduction Steps

  1. Set ~/.aws/config's default profile to have cli_pager=
  2. Open a new PowerShell Window
  3. Run [System.Environment]::SetEnvironmentVariable("AWS_PAGER","")
  4. Assume your AWS profile of choice. I used an existing SSO session by setting $Env:AWS_PROFILE to the relevant profile name.
  5. Run a CLI paginated AWS CLI command, such as the describe-instances command above. The output is be paginated.

Possible Solution

I use both Windows and Linux and haven't seen this same behaviour exhibited by Linux. I therefore suspect that this is just an oversight in how Windows handles variables.

Additional Information/Context

  • I don't set any AWS environment variables in my $PROFILE
  • I am using aws-cli/2.13.25 Python/3.11.5 Windows/10 exe/AMD64 prompt/off
  • I am using Powershell version 7.3.9

CLI version used

aws-cli/2.13.25 Python/3.11.5 Windows/10 exe/AMD64 prompt/off

Environment details (OS name and version, etc.)

Windows 10 Business 10.0.19045

jimbo8098 avatar Nov 22 '23 20:11 jimbo8098

Hi @jimbo8098, thanks for reaching out. I'm still investigating this issue, but I wanted bring up that I think cli_pager = is actually working correctly. Your reproduction steps are setting both though, and from the environment variables docs, AWS_PAGER overrides cli_pager = .

I've been able to reproduce the issue with AWS_PAGER and am trying to root cause the problem.

RyanFitzSimmonsAK avatar Nov 30 '23 00:11 RyanFitzSimmonsAK

My default Powershell profile .ps1 nor the default environment variables include a definition for AWS_PAGER. Here are the commands run in a newly opened Powershell window:

> echo "`"$Env:AWS_PAGER`""
""
> $Env:AWS_PAGER=""
> echo "`"$Env:AWS_PAGER`""
""
> $Env:AWS_PAGER="less"
> echo "`"$Env:AWS_PAGER`""
"less"

When cli_pager is not present in the AWS profile alongside $Env:AWS_PAGER set to "", paginated output is shown.

I suspect the environment variable is being interpreted incorrectly. Perhaps some oversight in how scopes in Windows might be different and the aspect of comparitors in Powershell specifically being a bit more advanced than a usual if[] block in Bash.

You have $Env:AWS_PAGER, sure, but you also have local scope with AWS_PAGER and also the machine level scope commonly set through setx or the environment variable dialog. Commonly, I'd expect that setting $Env:AWS_PAGER is most useful for a setting you wish to have persist temporarily for a Powershell terminal session, which is what I'd expect of this kind of definition. The cli_pager on the other hand would be a more persistent setting, remaining beyond just that session.

The presence of cli_pager= in the config file for the given profile works as expected. I was previously setting the default profile to use cli_pager= but this wasn't affecting the pagination but this is fine when set at a named profile scope. I had misread the documentation assuming this to set the default value for this which was incorrect.

jimbo8098 avatar Dec 01 '23 15:12 jimbo8098

In PowerShell, and in Windows in general, empty string environment variables are poorly supported (with an exception, see below). Setting an environment variable to an empty string is interpreted by client tools as unsetting the variable.

That is,

C:\Users\tom>set AWS_PAGER=test

C:\Users\tom>set AWS_PAGER
AWS_PAGER=test

C:\Users\tom>set AWS_PAGER=

C:\Users\tom>echo %AWS_PAGER%
%AWS_PAGER%

C:\Users\tom>set AWS_PAGER
Environment variable AWS_PAGER not defined

Here we set the AWS_PAGER variable to test, read it back, then set it to and can't read it back anymore. This is because set interprets empty string as deleting the variable. PowerShell follows the same semantics:

~ ❯ ls env:/AWS_PAGER
Get-ChildItem: Cannot find path 'AWS_PAGER' because it does not exist.

~ ❯ $Env:AWS_PAGER="test"

~ ❯ ls env:/AWS_PAGER

Name                           Value
----                           -----
AWS_PAGER                      test

~ ❯ $Env:AWS_PAGER=""

~ ❯ ls env:/AWS_PAGER
Get-ChildItem: Cannot find path 'AWS_PAGER' because it does not exist.

There is a big difference between these shells though: cmd.exe will allow you to call set VARIABLE="" which sets %VARIABLE% to the literal string "", whereas PowerShell more intuitively interprets "" as null. That's also why using $null in PowerShell also unsets the variable. There are other API calls in Windows that you can use to set empty environment variables, but they are mostly undocumented and mostly unsupported.


An exception is a recent change to .NET 9, which does support empty environment variables. As of this message, .NET 9 is only in the Preview version of PowerShell.

PowerShell 7.5.0-preview.4
~ ❯ $Env:AWS_PAGER=$null

~ ❯ ls env:/AWS_PAGER
Get-ChildItem: Cannot find path 'AWS_PAGER' because it does not exist.

~ ❯ $Env:AWS_PAGER=""

~ ❯ ls env:/AWS_PAGER

Name                           Value
----                           -----
AWS_PAGER

Setting the environment variable this way, through a .NET 9 compatible client tool, does correctly disable the pager as documented.

kellertk avatar Sep 04 '24 22:09 kellertk

I think you're right Tom. I've done some more work in PS since and handling of vars which are empty just isn't supported in the same way as Linux. I think the problem is that in Linux, a bar can be empty but in Windows it is always either undefined or a string. When I tried to set a var to $null the var was just undefined and thus CLI_PAGER did not get obeyed.

I noted the same handling in the configure file too, but I think this is just down to the file being read into vars anyway.

Frustrating it is unhandled since it makes reading the help pages a tiresome experience in PS, which unfortunately is my main use of it. It's quicker to read the help articles in a docker container than in the Windows CLI command.

On Wed, 4 Sept 2024, 23:20 Tom Keller, @.***> wrote:

In PowerShell https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables, and in Windows in general, empty string environment variables are poorly supported (with an exception, see below). Setting an environment variable to an empty string is interpreted by client tools as unsetting the variable.

That is,

C:\Users\tom>set AWS_PAGER=test

C:\Users\tom>set AWS_PAGER AWS_PAGER=test

C:\Users\tom>set AWS_PAGER=

C:\Users\tom>echo %AWS_PAGER%%AWS_PAGER%

C:\Users\tom>set %AWS_PAGER% Environment variable %AWS_PAGER% not defined

Here we set the AWS_PAGER variable to test, read it back, then set it to and can't read it back anymore. This is because set interprets empty string as deleting the variable. PowerShell follows the same semantics:

~ ❯ ls env:/AWS_PAGERGet-ChildItem: Cannot find path 'AWS_PAGER' because it does not exist.

~ ❯ $Env:AWS_PAGER="test"

~ ❯ ls env:/AWS_PAGER

Name Value---- ----- AWS_PAGER test

~ ❯ $Env:AWS_PAGER=""

~ ❯ ls env:/AWS_PAGERGet-ChildItem: Cannot find path 'AWS_PAGER' because it does not exist.

There is a big difference between these shells though: cmd.exe will allow you to call set VARIABLE="" which sets %VARIABLE% to the literal string "", whereas PowerShell more intuitively interprets "" as null. That's also why using $null in PowerShell also unsets the variable. There are other API calls in Windows that you can use to set empty environment variables, but they are mostly undocumented and mostly unsupported.

An exception is a recent change to .NET 9 https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/9.0/empty-env-variable, which does support empty environment variables. As of this message, .NET 9 is only in the Preview version of PowerShell.

PowerShell 7.5.0-preview.4 ~ ❯ $Env:AWS_PAGER=$null

~ ❯ ls env:/AWS_PAGERGet-ChildItem: Cannot find path 'AWS_PAGER' because it does not exist.

~ ❯ $Env:AWS_PAGER=""

~ ❯ ls env:/AWS_PAGER

Name Value---- ----- AWS_PAGER

Setting the environment variable this way, through a .NET 9 compatible client tool, does correctly disable the pager as documented.

— Reply to this email directly, view it on GitHub https://github.com/aws/aws-cli/issues/8351#issuecomment-2330252226, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC6XUFCYO6JO47BIYJVP7M3ZU6BSDAVCNFSM6AAAAAA7W2D7HKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMZQGI2TEMRSGY . You are receiving this because you were mentioned.Message ID: @.***>

jimbo8098 avatar Sep 04 '24 22:09 jimbo8098

The config file does work properly for paging operation output, but --no-cli-pager and the config file not working for help is a known issue.

RyanFitzSimmonsAK avatar Sep 04 '24 22:09 RyanFitzSimmonsAK

You're right @RyanFitzSimmonsAK , I'll close this issue now since the other issue is tracking it. I've already weighed in on that issue so hopefully it helps people piece together the solution!

jimbo8098 avatar Sep 05 '24 09:09 jimbo8098

This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.

github-actions[bot] avatar Sep 05 '24 09:09 github-actions[bot]