19

現時点では、bashのロードには約2秒かかります。フラグを付けてbashを実行しまし-xたが、出力が表示され、PATHがcygwinに何度もロードされているように見えます。面白いことに、Linux環境で同じファイルを使用していますが、リロードの問題がなく、正常に動作します。次の原因で問題が発生する可能性がありますか?

if [ `uname -o` = "Cygwin" ]; then
    ....
fi
4

9 に答える 9

21

回答で指摘したように、問題は Cygwin の bash-completion パッケージです。迅速かつ簡単な修正は、bash 補完を無効にすることです。これを行う正しい方法は、Cygwin の setup.exe を実行し (必要に応じて再度ダウンロードします)、そのパッケージのアンインストールを選択することです。

より長い解決策は、ファイルを/etc/bash_completion.d調べて、必要のないファイルを無効にすることです。私のシステムでは、Bash の読み込み時間を遅くする最大の原因 (mailman、shadow、dsniff、および e2fsprogs) はすべてまったく何もしませんでした。

でファイルの名前を拡張子に変更すると、/etc/bash_completion.dその.bakスクリプトの読み込みが停止します。この方法でシステムの 1 つで選択した 37 個のスクリプトを除くすべてを無効にすると、bash_completion のロードにかかる平均時間が 95% (6.5 秒から 0.3 秒) 短縮されました。

于 2013-03-26T20:57:41.503 に答える
6

すべての回答は古いバージョンの bash_completion を参照しており、最近のbash_completion.

最新の bash_completion は/usr/share/bash-completion/completions、デフォルトでほとんどの補完ファイルをに移動しました。実行してシステム上のパスを確認してください

# pkg-config --variable=completionsdir bash-completion
/usr/share/bash-completion/completions

そこには多くのファイルがあり、各コマンドに 1 つずつありますが、各コマンドで最初に補完を使用するときにオンデマンドでロードされるため、これは問題ではありません。古い/etc/bash_completion.dものは互換性のために引き続きサポートされており、そこからのすべてのファイルはbash_completion起動時に読み込まれます。

# pkg-config --variable=compatdir bash-completion
/etc/bash_completion.d

このスクリプトを使用して、古いディレクトリに古いファイルが残っているかどうかを確認します。

#!/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

新しい(オンデマンドの)補完ディレクトリにも存在する互換ディレクトリ内のファイルのリストを出力します。それらの一部を保持する特定の理由がない限り、それらのファイルをすべて確認、バックアップ、および削除してください。

その結果、互換ディレクトリはほとんど空になります。

さて、最も興味深い部分は、bash起動が遅い理由を確認することです。を実行すると、非ログインの対話型bashシェルが開始されます。これは Cygwin ソース上にあり、次に. rc ファイルの 1 つから入手しない限り、これにはおそらく bash の補完は含まれません。( )を実行するか、 ( によって異なります) を開始するか、SSH 経由でログインすると、対話型のログインシェルが開始されます。スクリプト自体は、./etc/bash.bashrc~/.bashrcbash -lbash --loginCygwin Terminalcygwin.bat/etc/profile~/.bash_profile/etc/profile.sh/etc/profile.d

各ファイルのソースにかかる時間を確認できます。このコードは/etc/profile次の場所にあります。

for file in /etc/profile.d/*.$1; do
  [ -e "${file}" ] && . "${file}"
done

バックアップしてから、これに置き換えます。

for file in /etc/profile.d/*.$1; do
  TIMEFORMAT="%3lR ${file}"
  [ -e "${file}" ] && time . "${file}"
done

開始するbashと、各ファイルにかかった時間が表示されます。かなりの時間がかかるファイルを調査します。私の場合はbash_completion.shfzf.sh(fzf はファジー ファインダーであり、bash_completion を補完する非常に優れた機能です)。ここでの選択は、それを無効にするか、さらに調査することです. 私は bash でショートカットを使い続けたかったのでfzf、調査し、スローダウンの原因を見つけて最適化し、パッチを fzf のリポジトリに提出しました (うまくいけば受け入れられるでしょう)。

今、最も時間を費やしているのは - bash_completion.sh. 基本的にそのスクリプトのソースは/usr/share/bash-completion/bash_completion. そのファイルをバックアップしてから編集しました。最後のページには、 dir -for内のすべてのファイルをソースするループがあります。繰り返しますが、 と を追加し、起動が遅い原因となっているスクリプトを確認しました。(パッケージ)でした。調べてみると、サブシェル( )がループで複数回実行されていることがわかり、その部分をサブシェルを使わずに書き直して、スクリプトが速く動くようにしました。私はすでにパッチを fzf のリポジトリに提出しました。compat/etc/bash_completion.dTIMEFORMATtimezzz-fzffzf$()for

これらすべての速度低下の最大の理由はfork、Windows プロセス モデルでサポートされていないことです。Cygwin はそれをエミュレートする素晴らしい仕事をしましたが、実際の UNIX と比較すると非常に遅いです。それ自体ではほとんど作業を行わないサブシェルまたはパイプラインは、実行時間のほとんどをfork-ing に費やします。time echo msgたとえば、(Cygwin で 0.000 秒) と (Cygwin で 0.042 秒)の実行時間をtime echo $(echo msg)昼と夜で比較します。のechoコマンド自体の実行にそれほど時間はかかりませんが、サブシェルの作成には非常にコストがかかります。私の Linux システムでは、これらのコマンドはそれぞれ 0.000 秒と 0.001 秒かかります。Cygwin が持つ多くのパッケージは、Linux やその他の UNIX を使用する人々によって開発されており、変更せずに Cygwin 上で実行できます。当然のことながら、これらの開発者は、システムのパフォーマンスに大きな影響を与えていないため、サブシェル、パイプライン、およびその他の機能を便利な場所で自由に使用できますが、Cygwin では、これらのシェル スクリプトの実行速度が何十倍も何百倍も遅くなる可能性があります。

要するに、Cygwin でシェル スクリプトの動作が遅い場合は、fork呼び出し元を特定し、スクリプトを書き直してそれらを可能な限り排除します。たとえばcmd="$(printf "$1" "$2")"(サブシェルに 1 つのフォークを使用) は に置き換えることができますprintf -v cmd "$1" "$2"

少年、それは本当に長くなりました。ここまで読んでくれた人は真のヒーローです。ありがとう :)

于 2016-04-23T20:10:00.360 に答える
4

これが古いスレッドであることは知っていますが、今週 Cygwin を新規インストールした後も、まだこの問題が発生しています。

すべての bash_completion ファイルを厳選する代わりに、この行を使用して、自分のマシンにインストールされていないものに対して @me_and のアプローチを実装しました。これにより、bash の起動時間が大幅に短縮されました。

で、次/etc/bash_completion.dを実行します。

for i in $(ls|grep -v /); do type $i >/dev/null 2>&1 || mv $i $i.bak; done
于 2014-10-24T20:11:49.663 に答える
3

元の質問に関連する、古いスレッドに対する新しい回答PATH

他の回答のほとんどは、bash の起動に関するものです。bash -iシェル内で実行するときに読み込み時間が遅い場合は、それが当てはまる可能性があります。

私の場合、bash -i高速で実行されましたが、新しいシェルを開くたびに (ターミナルまたは xterm で)、非常に長い時間がかかりました。bash -l時間がかかっている場合は、ログイン時間です。

https://cygwin.com/faq/faq.html#faq.using.startup-slowの Cygwin FAQ にはいくつかのアプローチがありますが、私にはうまくいきませんでした。

PATH元の投稿者は、 を使用して診断したについて質問しましたbash -x。私も、bash -i高速であるにもかかわらず、bash -xl低速であり、PATH.

PATHログインプロセスがプログラムを実行し続け、適切なプログラムをすべて検索し続けるほど、途方もなく長いWindowsがありPATHました。

私の解決策: Windows を編集しPATHて余分なものを削除します。どの部分を削除したかはわかりませんが、ログイン シェルの起動は 6 秒から 1 秒未満になりました。

YMMV。

于 2015-03-11T20:11:51.033 に答える
2

私はかなり複雑な設定の企業ネットワークを使用していますが、cygwin の起動時間が本当に長くなってしまうようです。npeの回答に関連して、ここに記載されているいくつかの手順に従う必要がありました: https://cygwin.com/faq/faq.html#faq.using.startup-slow

AD クライアント システムのもう 1 つの原因は、DC 応答が遅いことです。これは、リモート DC アクセスを使用する構成でよく見られます。Cygwin DLL は、起動時にローカル キャッシュを作成するために、参加しているすべてのグループに関する情報を照会します。ローカル ファイルに独自の情報をキャッシュすることで、このプロセスを少し高速化できます。/etc への書き込みアクセス権を持つ Cygwin ターミナルで次のコマンドを実行します。

getent passwd $(id -u) > /etc/passwd
getent group $(id -G) > /etc/group

また、次のように設定/etc/nsswitch.confします。

passwd: files db
group: files db

これにより、Cygwin が AD ドメイン コントローラー (DC) に接続する必要性が制限されますが、リモート ディレクトリを一覧表示する場合など、DC から追加情報を取得することができます。

それを行ってcygserverを起動した後、cygwinの起動時間が大幅に短縮されました。

于 2015-06-01T15:02:13.963 に答える
0

上記の誰かが述べたように、考えられる問題の 1 つは、PATH 環境変数に含まれるパスが多すぎることです。cygwin はそれらすべてを検索します。/etc/profile を直接編集することを好みます。PATH 変数を cygwin 関連のパスに上書きするだけPATH="/usr/local/bin:/usr/bin"です。必要に応じてパスを追加します。

于 2015-10-19T03:27:21.987 に答える
0

不要な補完スクリプトを非アクティブ化するために、「minimizecompletion」という名前の Bash 関数を作成しました。

補完スクリプトは、複数の補完仕様を追加したり、シェル ビルドインの補完仕様を持つことができるため、スクリプト名を $PATH にある実行可能ファイルと比較するだけでは十分ではありません。

私の解決策は、ロードされたすべての補完仕様を削除し、補完スクリプトをロードして、新しい補完仕様が追加されたかどうかを確認することです。これに応じて、スクリプト ファイル名に .bak を追加して無効にするか、.bak を削除して有効にします。/etc/bash_completion.d 内の 182 個のスクリプトすべてに対してこれを行うと、36 個のアクティブな完了スクリプトと 146 個の非アクティブな完了スクリプトが発生し、Bash の起動時間が 50% 短縮されます (ただし、これはインストールされているパッケージに依存することは明らかです)。

この関数は、非アクティブ化された完了スクリプトもチェックして、新しくインストールされた Cygwin パッケージに必要なときにアクティブ化できるようにします。すべての変更は、すべてのスクリプトをアクティブにする引数 -a で元に戻すことができます。

# Enable or disable global completion scripts for speeding up Bash start.
#
# Script files in directory '/etc/bash_completion.d' are inactived
# by adding the suffix '.bak' to the file name; they are activated by
# removing the suffix '.bak'. After processing all completion scripts
# are reloaded by calling '/etc/bash_completion'
#
# usage:  [-a]
#         -a  activate all completion scripts
# output: statistic about total number of completion scripts, number of
#         activated, and number of inactivated completion scripts; the
#         statistic for active and inactive completion scripts can be
#         wrong when 'mv' errors occure
# return: 0   all scripts are checked and completion loading was
#             successful; this does not mean that every call of 'mv'
#             for adding or removing the suffix was successful
#         66  the completion directory or loading script is missing
#
minimizecompletion() {
  local arg_activate_all=${1-}
  local completion_load=/etc/bash_completion
  local completion_dir=/etc/bash_completion.d

  (
    # Needed for executing completion scripts.
    #
    local UNAME='Cygwin'
    local USERLAND='Cygwin'
    shopt -s extglob progcomp
    have() {
      unset -v have
      local PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
      type -- "$1" &>/dev/null && have='yes'
    }

    # Print initial statistic.
    #
    printf 'Completion scripts status:\n'
    printf '  total:       0\n'
    printf '  active:      0\n'
    printf '  inactive:    0\n'
    printf 'Completion scripts changed:\n'
    printf '  activated:   0\n'
    printf '  inactivated: 0\n'

    # Test the effect of execution for every completion script by
    # checking the number of completion specifications after execution.
    # The completion scripts are renamed depending on the result to
    # activate or inactivate them.
    #
    local completions total=0 active=0 inactive=0 activated=0 inactivated=0
    while IFS= read -r -d '' f; do
      ((++total))
      if [[ $arg_activate_all == -a ]]; then
        [[ $f == *.bak ]] && mv -- "$f" "${f%.bak}" && ((++activated))
        ((++active))
      else
        complete -r
        source -- "$f"
        completions=$(complete | wc -l)
        if (( $completions > 0 )); then
          [[ $f == *.bak ]] && mv -- "$f" "${f%.bak}" && ((++activated))
          ((++active))
        else
          [[ $f != *.bak ]] && mv -- "$f" "$f.bak" && ((++inactivated))
          ((++inactive))
        fi
      fi
      # Update statistic.
      #
      printf '\r\e[6A\e[15C%s' "$total"
      printf '\r\e[1B\e[15C%s' "$active"
      printf '\r\e[1B\e[15C%s' "$inactive"
      printf '\r\e[2B\e[15C%s' "$activated"
      printf '\r\e[1B\e[15C%s' "$inactivated"
      printf '\r\e[1B'
    done < <(find "$completion_dir" -maxdepth 1 -type f -print0)

    if [[ $arg_activate_all != -a ]]; then
      printf '\nYou can activate all scripts with %s.\n' "'$FUNCNAME -a'"
    fi
    if ! [[ -f $completion_load && -r $completion_load ]]; then
      printf 'Cannot reload completions, missing %s.\n' \
             "'$completion_load'" >&2
      return 66
    fi
  )

  complete -r
  source -- "$completion_load"
}

これは出力例と結果の時間です。

$ minimizecompletion -a
Completion scripts status:
  total:       182
  active:      182
  inactive:    0
Completion scripts changed:
  activated:   146
  inactivated: 0

$ time bash -lic exit
logout

real    0m0.798s
user    0m0.263s
sys     0m0.341s

$ time minimizecompletion
Completion scripts status:
  total:       182
  active:      36
  inactive:    146
Completion scripts changed:
  activated:   0
  inactivated: 146

You can activate all scripts with 'minimizecompletion -a'.

real    0m17.101s
user    0m1.841s
sys     0m6.260s

$ time bash -lic exit
logout

real    0m0.422s
user    0m0.092s
sys     0m0.154s
于 2016-01-22T21:30:32.507 に答える