All of the answers refer to older versions of bash_completion, and are irrelevant for recent bash_completion
.
Modern bash_completion moved most of the completion files to /usr/share/bash-completion/completions
by default, check the path on your system by running
# pkg-config --variable=completionsdir bash-completion
/usr/share/bash-completion/completions
There are many files in there, one for each command, but that is not a problem, since they are loaded on demand the first time you use completion with each command. The old /etc/bash_completion.d
is still supported for compatibility, and all files from there are loaded when bash_completion
starts.
# pkg-config --variable=compatdir bash-completion
/etc/bash_completion.d
Use this script to check if there are any stale files left in the old dir.
#!/bin/sh
COMPLETIONS_DIR="$(pkg-config --variable=completionsdir bash-completion)"
COMPAT_DIR="$(pkg-config --variable=compatdir bash-completion)"
for file in "${COMPLETIONS_DIR}"/*; do
file="${COMPAT_DIR}/${file#${COMPLETIONS_DIR}/}"
[ -f "$file" ] && printf '%s\n' $file
done
It prints the list of files in compat dir that are also present in the newer (on-demand) completions dir. Unless you have specific reasons to keep some of them, review, backup and remove all of those files.
As a result, the compat dir should be mostly empty.
Now, for the most interesting part - checking why bash
startup is slow.
If you just run bash
, it will start a non-login, interactive shell - this one on Cygwin source /etc/bash.bashrc
and then ~/.bashrc
. This most likely doesn't include bash completion, unless you source it from one of rc files. If you run bash -l
(bash --login
), start Cygwin Terminal
(depends on your cygwin.bat
), or log in via SSH, it will start a login, interactive shell - which will source /etc/profile
, ~/.bash_profile
, and the aforementioned rc files. The /etc/profile
script itself sources all executable .sh
files in /etc/profile.d
.
You can check how long each file takes to source. Find this code in /etc/profile
:
for file in /etc/profile.d/*.$1; do
[ -e "${file}" ] && . "${file}"
done
Back it up, then replace it with this:
for file in /etc/profile.d/*.$1; do
TIMEFORMAT="%3lR ${file}"
[ -e "${file}" ] && time . "${file}"
done
Start bash
and you will see how long each file took. Investigate files that take a significant amount of time. In my case, it was bash_completion.sh
and fzf.sh
(fzf is fuzzy finder, a really nice complement to bash_completion). Now the choice is to disable it or investigate further. Since I wanted to keep using fzf
shortcuts in bash, I investigated, found the source of the slowdown, optimized it, and submitted my patch to fzf's repo (hopefully it will be accepted).
Now for the biggest time spender - bash_completion.sh
. Basically that script sources /usr/share/bash-completion/bash_completion
. I backed up that file, then edited it. On the last page there is for
loop that sources all the files in compat
dir - /etc/bash_completion.d
. Again, I added TIMEFORMAT
and time
, and saw which script was causing the slow starting. It was zzz-fzf
(fzf
package). I investigated and found a subshell ($()
) being executed multiple times in a for
loop, rewrote that part without using a subshell, making the script work quickly. I already submitted my patch to fzf's repo.
The biggest reason for all these slowdowns is: fork
is not supported by Windows process model, Cygwin did a great job emulating it, but it's painfully slow compared to a real UNIX. A subshell or a pipeline that does very little work by itself spends most of it's execution time for fork
-ing. E.g. compare the execution times of time echo msg
(0.000s on my Cygwin) vs time echo $(echo msg)
(0.042s on my Cygwin) - day and night. The echo
command itself takes no appreciable time to execute, but creating a subshell is very expensive. On my Linux system, these commands take 0.000s and 0.001s respectively. Many packages Cygwin has are developed by people who use Linux or other UNIX, and can run on Cygwin unmodified. So naturally these devs feel free to use subshells, pipelines and other features wherever convenient, since they don't feel any significant performance hit on their system, but on Cygwin those shell scripts might run tens and hundreds of times slower.
Bottom line, if a shell script works slowly in Cygwin - try to locate the source of fork
calls and rewrite the script to eliminate them as much as possible.
E.g. cmd="$(printf "$1" "$2")"
(uses one fork for subshell) can be replaced with printf -v cmd "$1" "$2"
.
Boy, it came out really long. Any people still reading up to here are real heros. Thanks :)
--startuptime
, and what's going wrong with that .bashrc. You'll have better luck asking each question separately, and for the second question, explaining what specifically is going wrong. – Cully--startuptime
option for bash anywhere in the man page and also the web. I think these questions go together, so I asked them together. – AlleviationBash loads slowly in Cygwin
? It's not about your English, just trying to make a good question even better. – Bestrew