Vscode: Separate shell settings for tasks vs interactive

Created on 12 Oct 2017  路  20Comments  路  Source: microsoft/vscode

  • VSCode Version: 1.17.1
  • OS Version: OS X High Sierra

Steps to Reproduce:

  1. Customize terminal.integrated.shell or shellArgs
  2. Launch a task like npm: watch
  3. Task launches with customize settings

I've customized my terminal settings to launch tmux with a session based on the working directory like:

  "terminal.integrated.shell.osx": "/usr/local/bin/fish",
  "terminal.integrated.shellArgs.osx": [
    "-c",
    "tmux new-session -A -t vsc-(basename (pwd))-(pwd | md5)"
  ],

This works great with the interactive terminal, but it appears that Tasks will launch the command using a shell with those args by default as well. Instead of running the Task's command, this ends up just launching another tmux instance connected to that session.

I found this out today trying out writing a new VSCode extension, and the debugger wouldn't work. When I tried to launch the default extension debugging configuration it would just hang. I eventually realized that it was trying to launch npm: watch using those custom shell settings, so it was just hanging waiting on the tmux process.

I can work around it by customizing the tasks.json to override the shell, but this also requires changing the type to "process" since the "npm" doesn't support those options:

"taskName": "watch",
"type": "process",
"command": "npm",
"args": [
    "run", "watch"
],
// commenting this out, turns out this part isn't required
// "options": {
//     "shell": {
//         "executable": "bash"
//     }
// },

However, this doesn't work if I want to contribute to an open-source extension that uses the default task configuration.

It would be better if VSCode had separate settings for the shell used to run Tasks. It should default to a standard "safe" shell for the platform (i.e. bash or cmd.exe) to be more compatible, and this is probably what most developers will assume when writing tasks.json.

feature-request tasks

Most helpful comment

Two things to note: specifying a shell works with using type "shell". Actually it only makes sense for type shell since processes are executed directly without any shell. The reason why the above works for you under Mac is that the npm script has a #! in it point to an interpreter to use.

And you can specify the options globally in a tasks.json to be used by all tasks:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "options": {
        "shell": {
            "executable": "cmd.exe",
            "args": [
                "/d", "/c"
            ]
        }
    },
    "tasks": [
        {
            "taskName": "dir",
            "type": "shell",
            "command": "dir"
        }
    ]
}

The executes dir using cmd.exe on my system although my default shell is PS.

All 20 comments

Two things to note: specifying a shell works with using type "shell". Actually it only makes sense for type shell since processes are executed directly without any shell. The reason why the above works for you under Mac is that the npm script has a #! in it point to an interpreter to use.

And you can specify the options globally in a tasks.json to be used by all tasks:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "options": {
        "shell": {
            "executable": "cmd.exe",
            "args": [
                "/d", "/c"
            ]
        }
    },
    "tasks": [
        {
            "taskName": "dir",
            "type": "shell",
            "command": "dir"
        }
    ]
}

The executes dir using cmd.exe on my system although my default shell is PS.

@dbaeumer Is there a way to set this for Windows only? We share tasks.json in our repo so I cannot force cmd.exe on my teammates on Macs :) Something like:

  "options": {
    "shell.windows": {
      "executable": "cmd.exe",
      "args": [
        "/d",
        "/c"
      ]
    }
  },

BTW, I need to set cmd.exe because with my default terminal configured to use Git Bash like this in my user settings.json:

    "terminal.integrated.shell.windows": "C:\\Program Files\\Git\\git-cmd.exe",
    "terminal.integrated.shellArgs.windows": [
        "--command=usr/bin/bash.exe",
        "-l",
        "-i"
    ],

and a task like this:

    {
      "taskName": "lint portal client",
      "type": "shell",
      "command": "yarn run lint",
      "options": {
        "cwd": "${workspaceRoot}/user-portal/client"
      },
      "problemMatcher": {
        "base": "$tslint5",
        "fileLocation": "absolute"
      },
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    },

I get this error:

> Executing task: yarn run lint <

bash: /d: Is a directory
The terminal process terminated with exit code: 126

Not sure if it's my misconfiguration or a VSCode bug..

Yes, there is:

    "windows": {
        "options": {
            "shell": {
                "executable": "cmd.exe",
                "args": [
                    "/d", "/c"
                ]
            }
        }
    }

Thanks, works like a charm!

Do you think https://github.com/Microsoft/vscode/issues/36154#issuecomment-336398547 is a bug? I'd open a separate issue for it if it is.

Yes and no. If we don't know the shell we assume cmd.exe command line args. May be we should change this to nothing. Please file an issue and I will think about what the best solution will be.

Done: #36216

@dbaeumer thanks, yeah that makes more sense that "process" should run directly without a shell, I had been experimenting with various configs and missed that the shell part wasn't necessary in that setup.

I'm assuming "npm" tasks are run in a shell for the benefit of tasks that behave differently in an interactive terminal, like applying coloring or fancy progress bars.
When "npm" tasks are run in a shell, shouldn't they also honor the "shell" option in tasks.json if one is configured?

For now I've implemented a different workaround by pointing "terminal.integrated.shell.osx" to this custom script that will choose the shell based on whether it was given args to run:

#!/usr/bin/env fish
if test -n "$argv"
  exec bash -l $argv
end
exec tmux new-session -A -t vsc-(basename (pwd))-(pwd | md5)

With this change I can use the default launch.json and tasks.json from the auto-generated extension code.

However, I still think it would save users from some confusion if there was another way to configure the shell so that the one used for interactive sessions didn't also affect the default config for tasks. I see there are similar issues opened by Windows users that want to use PowerShell or bash and then encountering errors with tasks.

@mgood nice trick.

Things must run in a shell if they are scripts like npm. Under Linux / Mac the interpreter is picked automatically using #! but this doesn't work under Windows.

@dbaeumer I prefer my personal shell to be Cygwin/ZSH, but the tasks runner does not work with that. I would love to be able to set my integrated terminal shell to Cygwin/ZSH but let the tasks run in cmd/powershell/whatever makes them happy. I would rather not have to configure that per-project in tasks.json, but if it works, it works, until there's something better. But that isn't working for me.

When I try to run a task:

> Executing task: node_modules\.bin\gulp.cmd watch <

cygpath: option requires an argument -- c
Try `cygpath --help' for more information.
Starting /bin/zsh
$

tasks.json:

{
    "version": "2.0.0",
    "windows": {
        "options": {
            "shell": {
                "executable": "cmd.exe",
                "args": [
                    "/d", "/c"
                ]
            }
        }
    },
    "tasks": [
        {
            "type": "gulp",
            "task": "watch",
            "problemMatcher": [
                "$tsc-watch",
                "$lessCompile"
            ]
        }
    ]
}

User settings:

{
    "terminal.integrated.shell.windows": "C:\\Tools\\Cygwin\\bin\\bash.exe",
    "terminal.integrated.shellArgs.windows": ["/bin/xhere", "/bin/zsh"],
}

@firelizzard18 the problem is caused by the fact that the task is actually coming from the gul auto detection and the tasks.json setting simply configures that tasks. I have an issue to decide what to do with auto detected tasks and shell settings. So this is currently not working but will be addressed in one the next releases.

I would still prefer system-specific configuration (user settings, not workspace settings) for the terminal to use for tasks. So I can say, "On this computer, I want to use some weird bizarre configuration for my interactive terminals, but use this other configuration to run tasks." So if another developer absolutely loves TCL/SH and I absolutely love ZSH, we can both configure our interactive terminals for that and the task terminals for powershell or w/e, but we don't have to pollute the repository with workspace settings that only matter for the two of us (assuming no other devs have made customizations incompatible with the tasks runner).

The shell setting override duplicates https://github.com/Microsoft/vscode/issues/36342

The request to have separare global terminal settings for task is treated as a feature request.

Is #36342 really the same? It's hard to tell because that issue doesn't specify... anything. I am looking for a very specific solution: I want user settings for the shell used for tasks that is independent of the settings for the interactive shell.

I want to see terminal.integrated.* settings duplicated as terminal.tasks.*. Should I create a separate feature request? I thought this issue covered the same ground, so I decided another issue would be redundant.

@firelizzard18 What you want is this issue. This is why it is still open.

@dbaeumer your example of how to use cmd.exe as the task shell, instead of the terminal.integrated one, was extremely helpful. I think the shell executable option should be discussed in the tasks.json docs somewhere. Should I file a separate issue for that?

@thw0rted yes, please file an issue against https://github.com/Microsoft/vscode-docs

Even though this issue claims the same settings are used between the VSC Terminal shell and the VSC Task shell, I'm finding that _there is actually some difference between the two_. In my case, RVM is configured correctly in a Terminal shell, but not in a Task shell. I've posted more details about by issue on StackOverflow rather than derailing here, in case someone following this issue might be able to offer some help. Thanks

Even though this issue claims the same settings are used between the VSC Terminal shell and the VSC Task shell, I'm finding that _there is actually some difference between the two_. In my case, RVM is configured correctly in a Terminal shell, but not in a Task shell. I've posted more details about by issue on StackOverflow rather than derailing here, in case someone following this issue might be able to offer some help. Thanks
@jameswilson did you find a workaround for your issue? I seem to be having the same problem but with conda (a program that manages my python env similar to your issue with rvm).

With https://github.com/microsoft/vscode/issues/78497 we now have a way to override the default shell for tasks. When that setting isn't set, we use whatever was set with terminal.integrated.shell.*, but when the setting is set, ignore the shellArgs in settings and use the newly set automation shell for tasks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lukehoban picture lukehoban  路  3Comments

trstringer picture trstringer  路  3Comments

omidgolparvar picture omidgolparvar  路  3Comments

ryan-wong picture ryan-wong  路  3Comments

trstringer picture trstringer  路  3Comments