task: Cannot correctly modify environment variable PATH for use in task commands

  • Task version: 2.5.1
  • OS: Windows 10 Professional (64-bit)
  • Example Taskfile showing the issue:
# https://taskfile.dev

version: '2'

tasks:

  a:
    cmds:
      - echo "Task a"
      - echo $PATH

  b:
    cmds:
      - echo "Task b"
      - echo "{{.PATH}}"

  c:
    env:
      PATH: tools
    cmds:
      - echo "Task c"
      - echo $PATH

  d:
    env:
      PATH: tools
    cmds:
      - echo "Task d"
      - echo "{{.PATH}}"

  e:
    env:
      PATH:
        sh: echo "tools;$PATH"
    cmds:
      - echo "Task e"
      - echo $PATH

  f:
    env:
      PATH:
        sh: echo "./tools;$PATH"
    cmds:
      - echo "Task f"
      - echo $PATH

  g:
    env:
      PATH:
        sh: echo "$(realpath ./tools);$PATH"
    cmds:
      - echo "Task g"
      - echo $PATH

Hello. Firstly, thank-you for Task. It has, overall, made my development life easier and more pleasant.

I don’t know if the problem I have is a bug or if I simply don’t understand the correct way to achieve my goal. I’d like to be able to modify the environment variable PATH (either prepending or appending a project-specific directory to the existing value), but I can’t figure out how to do this using the set of commands available within Taskfiles.

To provide context, my Taskfile is for use in building go applications. Some applications (projects) require project-specific build tools/helpers that I place in a top-level tools subdirectory (i.e., <project name>/tools). Note that my Taskfile resides at <project name>/Taskfile.yml. I wish to use the go generate command, which effectively requires that external generation tools be accessible via PATH, so I must add <project name>/tools to PATH before running go generate in the task.

While I’m working in Windows, I’m making effective use of busybox-w32 to provide a fairly comprehensive set of what are otherwise Linux tools, so things like cp, echo and realpath are available. I’ve also tried this via WSL such that things are more like a real Linux environment, with the same results.

The output I get from the above Taskfile (when run under sh or bash via WSL) is as follows (results in native Windows are the same):

$ task a; task b; task c; task d; task e; task f; task g                                             
echo "Task a"                                                                                        
Task a                                                                                               
echo $PATH                                                                                           
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games             
echo "Task b"                                                                                        
Task b                                                                                               
echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"      
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games             
echo "Task c"                                                                                        
Task c                                                                                               
echo $PATH                                                                                           
tools                                                                                                
echo "Task d"                                                                                        
Task d                                                                                               
echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"      
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games             
echo "Task e"                                                                                        
Task e                                                                                               
echo $PATH                                                                                           
tools;/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games       
echo "Task f"                                                                                        
Task f                                                                                               
echo $PATH                                                                                           
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games             
echo "Task g"                                                                                        
Task g                                                                                               
echo $PATH                                                                                           
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

Tasks a, b, c and d are just simple tests; it’s tasks e, f and g that illustrate the real issue. Task e works correctly, prepending tools to the current PATH, but neither f nor g have any effect. Task g is the closest to what I need in terms of operations (i.e., adding the absolute path of a project-specific directory).

I’d greatly appreciate any input you could provide on this issue. Thanks in advance.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 17 (9 by maintainers)

Most upvoted comments

Came here via Google, so for reference: Same here, running Linux (Fedora 37 wit go-task installed via DNF - reported version is “unknown”, but RPM says 3.20.0). Installing v3.21.0 from releases worked though.

Or not 😕 might have myt test cases mixed up, sorry…

version: '3'

vars:
  PYTHON_VERSION:
    sh: cat runtime.txt
  PATH:
    sh: echo $PATH
  PYTHON_PATH: '/usr/bin/python{{ trim .PYTHON_VERSION }}'
  VENV_PATH: '{{.PWD}}/.venv'
  NEW_PATH: "{{.VENV_PATH}}/bin:{{.PATH}}"


env:
  PATH: "{{.NEW_PATH}}"
  NEW_PATH: "{{.NEW_PATH}}"

tasks:
  py:
    cmds:
      - echo "$NEW_PATH"
      - echo "$PATH"
      - export PATH="$NEW_PATH"
      - echo "$PATH"
      - PATH="$NEW_PATH/bin:$PATH" echo $PATH
      - echo "({{.PYTHON_VERSION}}) {{.PYTHON_PATH}}"
% go-task py        
task: [py] echo "$NEW_PATH"
/tmp/test/.venv/bin:/usr/share/Modules/bin:/home/…
task: [py] echo "$PATH"
/usr/share/Modules/bin:/home/…
task: [py] export PATH="$NEW_PATH"
task: [py] echo "$PATH"
/usr/share/Modules/bin:/home/…
task: [py] PATH="$NEW_PATH/bin:$PATH" echo $PATH
/usr/share/Modules/bin:/home/…
task: [py] echo "(3.11) /usr/bin/python3.11"
(3.11) /usr/bin/python3.11

Probably b/c https://github.com/go-task/task/issues/482

@i-am-david-fernandez Sorry, I’ll take long to debug this since my available time has being low recently, and I don’t use Windows often nowadays. I do plan to debug and fix this, though.


Just a friendly reminder that @mvdan has no interest in Task, and likely won’t digest a long thread like this to understand the problem. If we think we found a problem on mvdan/sh we should try to reproducing it in a small Go script (importing the sh’s packages directly) and open a more specific issue there.

I should note that I’ve been providing output produced via WSL under the assumption that its closeness to Linux makes it more useful from a debugging perspective. My working environment is Powershell in native Windows and that’s where I’m most interested in having this work.

I apologise if the WSL stuff has become a distraction.

Here’s the output from Powershell of the first Taskfile I posted (the opening post in this thread):

echo "Task a"
Task a
echo $PATH
C:\PortablePrograms\ConEmu\ConEmu\Scripts:C:\PortablePrograms\ConEmu:C:\PortablePrograms\ConEmu\ConEmu:C:\WINDOWS\system32:C:\WINDOWS:C:\WINDOWS\System32\Wbem:C:\WINDOWS\System32\WindowsPowerShell\v1.0\:C:\WINDOWS\System32\OpenSSH\:C:\Program Files\Git\cmd:C:\Program Files (x86)\HashiCorp\Vagrant\bin:C:\Users\AppData\Local\Microsoft\WindowsApps:C:\Users\AppData\Local\Programs\Microsoft VS Code\bin:C:\Users\AppData\Local\Programs\Fiddler:C:\PortablePrograms\bin:C:\PortablePrograms\Busybox
echo "Task b"
Task b
echo "<no value>"
<no value>
echo "Task c"
Task c
echo $PATH
tools
echo "Task d"
Task d
echo "<no value>"
<no value>
echo "Task e"
Task e
echo $PATH
tools:C:\PortablePrograms\ConEmu\ConEmu\Scripts:C:\PortablePrograms\ConEmu:C:\PortablePrograms\ConEmu\ConEmu:C:\WINDOWS\system32:C:\WINDOWS:C:\WINDOWS\System32\Wbem:C:\WINDOWS\System32\WindowsPowerShell\v1.0\:C:\WINDOWS\System32\OpenSSH\:C:\Program Files\Git\cmd:C:\Program Files (x86)\HashiCorp\Vagrant\bin:C:\Users\AppData\Local\Microsoft\WindowsApps:C:\Users\AppData\Local\Programs\Microsoft VS Code\bin:C:\Users\AppData\Local\Programs\Fiddler:C:\PortablePrograms\bin:C:\PortablePrograms\Busybox
echo "Task f"
Task f
echo $PATH
C:\PortablePrograms\ConEmu\ConEmu\Scripts:C:\PortablePrograms\ConEmu:C:\PortablePrograms\ConEmu\ConEmu:C:\WINDOWS\system32:C:\WINDOWS:C:\WINDOWS\System32\Wbem:C:\WINDOWS\System32\WindowsPowerShell\v1.0\:C:\WINDOWS\System32\OpenSSH\:C:\Program Files\Git\cmd:C:\Program Files (x86)\HashiCorp\Vagrant\bin:C:\Users\AppData\Local\Microsoft\WindowsApps:C:\Users\AppData\Local\Programs\Microsoft VS Code\bin:C:\Users\AppData\Local\Programs\Fiddler:C:\PortablePrograms\bin:C:\PortablePrograms\Busybox
echo "Task g"
Task g
echo $PATH
D:/Projects/Taskfiles/scratch/tools:C:\PortablePrograms\ConEmu\ConEmu\Scripts:C:\PortablePrograms\ConEmu:C:\PortablePrograms\ConEmu\ConEmu:C:\WINDOWS\system32:C:\WINDOWS:C:\WINDOWS\System32\Wbem:C:\WINDOWS\System32\WindowsPowerShell\v1.0\:C:\WINDOWS\System32\OpenSSH\:C:\Program Files\Git\cmd:C:\Program Files (x86)\HashiCorp\Vagrant\bin:C:\Users\AppData\Local\Microsoft\WindowsApps:C:\Users\AppData\Local\Programs\Microsoft VS Code\bin:C:\Users\AppData\Local\Programs\Fiddler:C:\PortablePrograms\bin:C:\PortablePrograms\Busybox

I clearly missed that task g partially works: the PATH as displayed has stuff prepended, but, whether because slashes are wrong or semi-colons have been swapped with colons, the end result isn’t correct (I tried running something from that prepended path via the task and it fails as it can’t find it in PATH).

For ease of reference, here is task g:

  g:
    env:
      PATH:
        sh: echo "$(realpath ./tools);$PATH"
    cmds:
      - echo "Task g"
      - echo $PATH

Changing the method of specifying the PATH from echo "$(realpath ./tools);$PATH" to sh: echo "$(pwd)\tools;$PATH" resolves the slash issue:

echo "Task g"
Task g
echo $PATH
D:\Projects\Taskfiles\scratch\tools:C:\PortablePrograms\ConEmu\ConEmu\Scripts:C:\PortablePrograms\ConEmu:C:\PortablePrograms\ConEmu\ConEmu:C:\WINDOWS\system32:C:\WINDOWS:C:\WINDOWS\System32\Wbem:C:\WINDOWS\System32\WindowsPowerShell\v1.0\:C:\WINDOWS\System32\OpenSSH\:C:\Program Files\Git\cmd:C:\Program Files (x86)\HashiCorp\Vagrant\bin:C:\Users\AppData\Local\Microsoft\WindowsApps:C:\Users\AppData\Local\Programs\Microsoft VS Code\bin:C:\Users\AppData\Local\Programs\Fiddler:C:\PortablePrograms\bin:C:\PortablePrograms\Busybox

But, perhaps because of the colons, still doesn’t ultimately work.