Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: script-friendly output of nvm ls, ls-remote, alias #2005

Closed
jcsahnwaldt opened this issue Feb 23, 2019 · 11 comments
Closed

Comments

@jcsahnwaldt
Copy link
Contributor

While trying to write a bash script that solves #1792, I noticed that it's not easy to process the output of nvm ls or nvm ls-remote. It would be nice to have an option to make these commands produce output that is suitable for scripts.

Maybe something like this:

  • each version in one line (the commands already do that)
  • each line contains only the version number, nothing else
  • no colors
  • nvm ls should list
    • only installed versions (no versions that are N/A)
    • no mappings from alias names to version numbers
    • no indication which version is currently in use
  • nvm ls-remote should list
    • all available versions
    • no version names (like (LTS: Dubnium))
    • no indication which versions are installed

In the case of nvm ls, there's a simple workaround that should work in many cases: just use ls -1 ~/.nvm/versions/node/ instead. But there's no such workaround for nvm ls-remote and nvm alias.

@jcsahnwaldt
Copy link
Contributor Author

Here's what's problematic about the current output:

  • nvm ls and nvm ls-remote usually produce colorized output, but scripts can't handle color codes.
  • When I disable colors with nvm ls --no-colors or TERM=dumb nvm ls, the output now contains a * after each installed version.
    • A script would have to strip these asterisks before it can process the version numbers.
  • The lines listing aliases contain not just a version number, but also a ->, for example default -> 6.4 (-> v6.4.0). I could remove these lines with grep -v -e '->', but...
  • ...the line for the version currently in use also contains a -> (at the start of the line), and a script usually wants to include the current version. To remove all alias lines but include the current version, I could use grep -v -E -e '.+->'.

And so on. It's no fun.

@jcsahnwaldt
Copy link
Contributor Author

jcsahnwaldt commented Feb 23, 2019

Of course, different scripts have different requirements. Some scripts may need...

  • ...the information which versions are already installed when they process the output of nvm ls-remote,
  • ...the mappings from alias names to version numbers in the output of nvm ls,
  • ...which version is currently in use, and so on...

Such scripts could probably combine and filter the output of nvm ls, nvm ls-remote, nvm alias, and/or nvm current if it's in the script-friendly format suggested above. In most cases, that shouldn't be too hard with the usual tools (awk, grep, etc.).

But maybe a less simplistic format would make life easier for such scripts:

  • multiple columns per line, not just the version number
  • columns separated by tabs (tabs usually work better than space, semicolons or commas)
  • all lines have the same format (same number of columns)
  • nvm ls and nvm ls-remote should have the same format (as far as possible)

Which columns would make sense? I don't know enough about the data currently produced by nvm ls and `nvm ls-remote', but...

  • ...something like installed=yes|no would probably be useful
  • ...maybe also alias=default,node,stable or something like that.
    • Or maybe it would be better to list one alias per line, as nvm ls and nvm alias currently do.
  • ...are the LTS names of nvm ls-remote (like (LTS: Dubnium)) useful? I don't know.

@jcsahnwaldt
Copy link
Contributor Author

Maybe it would be nice to have multiple options for the output, e.g. nvm ls --no-alias, nvm ls-remote --omit-installed, etc. But I guess I'm already asking for a lot, so I'll stop. :-)

@ljharb
Copy link
Member

ljharb commented Feb 23, 2019

As you said, different scripts have different requirements. The no-colors version is what I’d build off of; the asterisks are necessary so scripts and humans can know which is installed. You can use cut or awk to trivially split on spaces, for example.

Since aliases can be most any string, it’s important to see what they resolve to - it wouldn’t be useful to just list the alias, or just the resolved value.

Can you elaborate on precisely what you want to do that you find hard?

@ljharb
Copy link
Member

ljharb commented Feb 23, 2019

(also note your ls workaround is not robust; not everything is in the versions folder or the versions/node folder)

@jcsahnwaldt
Copy link
Contributor Author

jcsahnwaldt commented Feb 23, 2019

I tried to solve #1792: uninstall all x.* versions. In my case, I had installed about twenty different versions (from 0.x to 10.x) because I had run compatibility tests and now wanted to delete most of them. I looked at the output of nvm ls --no-colors and found that the output is not suitable for scripts:

  • the lines I may need can have between one and three columns
  • the column I need is either the first or second column
  • the lines I don't need contain the characters -> (or is there a better way to distinguish the alias lines from the version lines?)
  • but one of the lines I do need may also contain the characters ->, so I have to make sure I don't drop that line...

Of course, it's possible to handle all of these things in a script, but it's rather awkward. For example, cut doesn't work because the version number is preceded by a variable number of spaces. I could first pipe the ouput of nvm ls --no-colors through awk, but... ough.

But anyway, I tried again and came up with a pipeline that seems to extract version numbers from the output of nvm ls:

nvm ls --no-colors | grep -v -E '.+->' | awk '{if (NF == 3) print $2; else print $1; }'

Not too bad, but... I guess my point is that almost all UNIX shell commands are made to play well with scripts. For example, ls detects when its output is not a terminal and automatically switches to -1 mode. And so on. That's what makes shell scripts so powerful. The output of nvm is different: Nice for humans, awkward for scripts.

@ljharb
Copy link
Member

ljharb commented Feb 23, 2019

nvm ls --no-colors | egrep -o 'v${major}.\d+.\d+' | uniq should work for any major.

@ljharb
Copy link
Member

ljharb commented Feb 23, 2019

If you can write a PR that can detect when nvm ls is being used in a pipe, i'd be happy to auto-switch the format of many nvm commands when being piped.

@jcsahnwaldt
Copy link
Contributor Author

jcsahnwaldt commented Feb 23, 2019

I found this on Stack Overflow. Seems to work on my machine (macOS 10.13.6, tested in GNU bash 3.2.57 and zsh 5.3):

test_term() {
  local IS_TERMINAL
  if [ -t 1 ]; then
    IS_TERMINAL=true
   fi
  echo $IS_TERMINAL
}

Result: test_term prints true, but test_term | cat prints an empty line (because IS_TERMINAL is not set).

I'd be happy to create a PR, but I'm not sure where to put this in nvm.sh. I guess a function like nvm_is_zsh() would work?

nvm_is_terminal() {
  [ -t 1 ]
}

I created PR #2007. Let me know what you think.

@jcsahnwaldt
Copy link
Contributor Author

Auto-switching the format of many nvm commands sounds great. As you mentioned at #1792, it would probably be best to have a --no-alias option for nvm ls. I guess most scripts don't need the alias list. But dropping the alias list automatically when nvm detects a pipe would probably be confusing, so an explicit option sounds good.

@ljharb
Copy link
Member

ljharb commented Mar 5, 2020

nvm ls --no-alias works, as does TERM=DUMB nvm ls --no-alias and nvm ls --no-alias --no-colors. In general, all colorized output should not be colorized when using a terminal that doesn't support it (TERM=dumb being an easy way to force that, and commands should already support --no-color). Additionally, when not colorized, information usually conveyed by colorization is conveyed by an easily awk-able column, like an asterisk in nvm ls's case.

Please file a new issue if your needs still aren't met :-)

@ljharb ljharb closed this as completed Mar 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants