How to setup an external command to indent bash script?

125 views
Skip to first unread message

Peng Yu

unread,
Apr 2, 2021, 5:52:46 PM4/2/21
to vim_use
I want to use shfmt to indent bash script in vim instead of using the
default vim indenter. Could anybody show me how to set this up in vim?

https://github.com/mvdan/sh#shfmt

shfmt -l -w script.sh

--
Regards,
Peng

Grant Taylor

unread,
Apr 2, 2021, 6:10:18 PM4/2/21
to vim...@googlegroups.com
On 4/2/21 3:52 PM, Peng Yu wrote:
> I want to use shfmt to indent bash script in vim instead of using the
> default vim indenter. Could anybody show me how to set this up in vim?

I would play with the formatprg setting.

:help formatprg

> shfmt -l -w script.sh

Based on my read of the help section, it looks like formatprg expects to
read STDIN and write to STDOUT. So you might need some sort of wrapper
to read Vim's STDOUT to a file, shfmt said file, then write said file
back to Vim's STDIN.

But I suspect that this is eminently doable.



--
Grant. . . .
unix || die

Peng Yu

unread,
Apr 2, 2021, 6:16:08 PM4/2/21
to vim...@googlegroups.com
On 4/2/21, 'Grant Taylor' via vim_use <vim...@googlegroups.com> wrote:
> On 4/2/21 3:52 PM, Peng Yu wrote:
>> I want to use shfmt to indent bash script in vim instead of using the
>> default vim indenter. Could anybody show me how to set this up in vim?
>
> I would play with the formatprg setting.
>
> :help formatprg
>
>> shfmt -l -w script.sh
>
> Based on my read of the help section, it looks like formatprg expects to
> read STDIN and write to STDOUT. So you might need some sort of wrapper
> to read Vim's STDOUT to a file, shfmt said file, then write said file
> back to Vim's STDIN.

It can take the file from STDIN in this way. The output is to STDOUT.

shfmt /dev/stdin < script.sh

Could you show me the commands (that can be put in ~/.vimrc) to set
formatprg to `shfmt /dev/stdin` just for a file when it is determined
as a bash script? I don't want to mess it up for other file types.

>
> But I suspect that this is eminently doable.
>
>
>
> --
> Grant. . . .
> unix || die
>
> --
> --
> You received this message from the "vim_use" maillist.
> Do not top-post! Type your reply below the text you are replying to.
> For more information, visit http://www.vim.org/maillist.php
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "vim_use" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/vim_use/D1sH4gr3LZA/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> vim_use+u...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/vim_use/ed861df1-0a61-cae5-dfd9-8c576d664e92%40spamtrap.tnetconsulting.net.
>


--
Regards,
Peng

Grant Taylor

unread,
Apr 2, 2021, 7:29:28 PM4/2/21
to vim...@googlegroups.com
On 4/2/21 4:16 PM, Peng Yu wrote:
> It can take the file from STDIN in this way. The output is to STDOUT.

Even better.

> Could you show me the commands...

I don't know as I've not used formatprg in recent memory.

I'd try interactively setting it and testing it with a file.

Quickly poking at things looks like:

:set formatprg=/path/to/shfmt

Give it a try. Please let us know what you find out.

Gary Johnson

unread,
Apr 2, 2021, 7:41:11 PM4/2/21
to vim...@googlegroups.com
On 2021-04-02, Peng Yu wrote:
> On 4/2/21, 'Grant Taylor' via vim_use <vim...@googlegroups.com> wrote:
> > On 4/2/21 3:52 PM, Peng Yu wrote:
> >> I want to use shfmt to indent bash script in vim instead of using the
> >> default vim indenter. Could anybody show me how to set this up in vim?
> >
> > I would play with the formatprg setting.
> >
> > :help formatprg
> >
> >> shfmt -l -w script.sh
> >
> > Based on my read of the help section, it looks like formatprg expects to
> > read STDIN and write to STDOUT. So you might need some sort of wrapper
> > to read Vim's STDOUT to a file, shfmt said file, then write said file
> > back to Vim's STDIN.
>
> It can take the file from STDIN in this way. The output is to STDOUT.
>
> shfmt /dev/stdin < script.sh
>
> Could you show me the commands (that can be put in ~/.vimrc) to set
> formatprg to `shfmt /dev/stdin` just for a file when it is determined
> as a bash script? I don't want to mess it up for other file types.
>
> >
> > But I suspect that this is eminently doable.

Since you want to indent rather than format, a better choice of
options would be 'equalprg'. See

:help 'equalprg'

The 'equalprg' option is global or local to buffer, so you can set
it locally for the sh filetype and not have to worry about it
affecting other buffers.

You can enable it in your vimrc for sh and bash files like this:

au FileType sh setlocal equalprg=shfmt

Without any arguments, shfmt reads from stdin and writes to stdout,
just what you need here.

This won't automatically indent as you type--you'll have to execute
the = command on a range of lines. See

:help =

For Vim to format automatically as you type, you'd have to use
'indentexpr' and shfmt isn't intended to work in that context.

According to the shfmt project page, https://github.com/mvdan/sh,
someone has written a Vim plugin for shfmt,
https://github.com/z0mbix/vim-shfmt. You may want to check that
out, too.

Regards,
Gary

Peng Yu

unread,
Apr 2, 2021, 9:00:26 PM4/2/21
to vim_use
> According to the shfmt project page, https://github.com/mvdan/sh,
> someone has written a Vim plugin for shfmt,
> https://github.com/z0mbix/vim-shfmt. You may want to check that
> out, too.

This probably is a better approach. I am trying to set it up. I use
pathogen. So I set it up like this.

~/.vim$ ls -dlgG bundle-available/vim-shfmt
drwxr-xr-x 7 224 2021/04/02-19:51:21 bundle-available/vim-shfmt
~/.vim$ ls -dlgG bundle/vim-shfmt
lrwxr-xr-x 1 29 2021/04/02-19:52:09 bundle/vim-shfmt ->
../bundle-available/vim-shfmt

It is not clear to me what instructions on
https://github.com/z0mbix/vim-shfmt I need to following, as its author
does not assume users use pathogen. Do you know?

https://github.com/z0mbix/vim-shfmt

As of now, when I try `:Shfmt -p`, vim shows this error.

Error detected while processing function shfmt#shfmt:
line 11:
Shfmt returned an error (often due to wrong syntax). Undoing changes.
9 more lines; before #1 0 seconds ago

--
Regards,
Peng

Peng Yu

unread,
Apr 2, 2021, 9:03:02 PM4/2/21
to vim_use
> You can enable it in your vimrc for sh and bash files like this:
>
> au FileType sh setlocal equalprg=shfmt

I put the above line in my ~/.vimrc. It just works. Thanks.

It seems that this is the simplest solution.

I don't know what is the advantage of the shfmt vim plugin is. Do you know?

--
Regards,
Peng

Gary Johnson

unread,
Apr 2, 2021, 9:49:49 PM4/2/21
to vim_use
On 2021-04-02, Peng Yu wrote:
> > According to the shfmt project page, https://github.com/mvdan/sh,
> > someone has written a Vim plugin for shfmt,
> > https://github.com/z0mbix/vim-shfmt. You may want to check that
> > out, too.
>
> This probably is a better approach. I am trying to set it up. I use
> pathogen. So I set it up like this.
>
> ~/.vim$ ls -dlgG bundle-available/vim-shfmt
> drwxr-xr-x 7 224 2021/04/02-19:51:21 bundle-available/vim-shfmt
> ~/.vim$ ls -dlgG bundle/vim-shfmt
> lrwxr-xr-x 1 29 2021/04/02-19:52:09 bundle/vim-shfmt ->
> ../bundle-available/vim-shfmt
>
> It is not clear to me what instructions on
> https://github.com/z0mbix/vim-shfmt I need to following, as its author
> does not assume users use pathogen. Do you know?

I'm afraid I'm of no help with that. I don't use Plug, pathogen or
shfmt. For a simple plugin like this one, I just copy the files
into ~/.vim/autoload and ~/.vim/plugin.

> https://github.com/z0mbix/vim-shfmt
>
> As of now, when I try `:Shfmt -p`, vim shows this error.
>
> Error detected while processing function shfmt#shfmt:
> line 11:
> Shfmt returned an error (often due to wrong syntax). Undoing changes.
> 9 more lines; before #1 0 seconds ago

For that, I would just look at the 11th line of shfmt#shfmt() and
see what the problem might be. I just did. It's in
autoload/shfmt.vim. That message is displayed when a shell error
results from passing a set of lines to the shfmt command with the
options you specify. Unfortunately, that command is preceded by
:silent so we can't see what the error was.

There are lots of ways to troubleshoot this. One way would be to
execute your command with :debug, like this:

:debug Shfmt -p

Then single step (using the s debug command) to line 9 of the
shfmt#shfmt() function. (It's a short function, so this won't be
hard.) As you execute that line, Vim will show you the command
being executed, with the variables expanded.

If that command looks OK to you but it still generates an error,
then you can try executing it from the Vim command line and see what
error message is displayed by shfmt. That may tell you what the
problem is.

If you're still having problems, post here what you've discovered.
Remember that I don't have shfmt installed so I won't be able to try
your examples.

Regards,
Gary

Gary Johnson

unread,
Apr 2, 2021, 9:50:43 PM4/2/21
to vim_use
On 2021-04-02, Peng Yu wrote:
No. I wondered that, too.

Regards,
Gary

Enno

unread,
Apr 5, 2021, 9:07:26 AM4/5/21
to vim_use
to the Readme of the vim-shfmt plugin explains how to set up &formatprg to indent shell scripts with shfmt.
Reply all
Reply to author
Forward
0 new messages