-2

サブディレクトリのメニューを表示し、ユーザーがcdするディレクトリを選択できるようにするksh関数 ( .profileファイルに配置される) を作成しています。コードは次のとおりです。

# Menu driven subdirectory descent.
d(){
# Only one command line argument accepted
[ "$1" = "--" ] && shift $# #   Trap for "ls --" feature
wd=`pwd`; arg="${1:-$wd}"
dirs="`/bin/ls -AF $arg  2>/dev/null | grep /$ | tr -d \"/\"`"
#       Set the names of the subdirectories to positional parameters
if [ "$dirs" ] ;then
        set $dirs
        if [ $# -eq 1 -a "$arg" = "$wd" ] ;then cd $arg/$1; return; fi # trap: it's obvious; do it
else echo "No subdirectories found" >&2; return 1
fi
#       Format and display the menu
if [ `basename "${arg}X"` = "${arg}X" ] ;then arg="$wd/$arg"; fi # Force absolute path if relitive
echo -e "\n\t\tSubdirectories relative to ${arg}: \n"
j=1; for i; do echo -e "$j\t$i"; j=`expr $j + 1`; done | pr -r -t -4 -e3 
echo -e "\n\t\tEnter the number of your choice -- \c "
#       Convert user-input to directory-name and cd to it
read choice; echo
dir=`eval "(echo $\{"$choice"\})"`  #       Magic here.
[ "$choice" -a "$choice" -ge 1 -a "$choice" -le "$#" ] && cd $arg/`eval echo "$dir"`
}

この関数は、スペース文字を含むディレクトリ名を除いて、かなりうまく機能します。ディレクトリ名にスペースが含まれている場合、setコマンドはディレクトリ名の (完全なディレクトリ名ではなく) スペースで区切られた各要素を個別の定位置パラメーターに設定します。それはここでは役に立ちません。

$IFSシェル変数 (デフォルトでspacetab、およびnewlineを含む) を単一の改行文字に設定しようとしました:

IFS=`echo`        # echo outputs a trailing newline character by default

これは、次の方法で検証された意図を達成しているように見えます。

echo -e "$IFS\c" | hexdump -c

しかし、私の最善の努力にもかかわらず (数日間の作業の過程で)、スペースを含むディレクトリ名全体を位置パラメーターの値として設定できませんでした。

私は何が欠けていますか?

提案はここに求められ、大歓迎です。

ADVAありがとうNCE

ボブ

4

3 に答える 3

0

まだ動作していませんが、このバージョンはshellcheckに合格しますが、1 つの例外があります。

3  # Menu driven subdirectory descent.
4  function d{
5  # Only one command line argument accepted
6  [ "$1" = "--" ] && shift $#        # Trap for "ls --" feature
7  wd="$PWD"; arg="${1:-$wd}"
8  set -- "${@%/}"              #       Set the names of the subdirectories to positional parameters
9  if [ $# -eq 1 -a "$arg" = "$wd" ] ;then cd "$arg/$1" || exit 1; return; # trap: it's obvious; do it
10  else echo "No subdirectories found" >&2; return 1
11  fi
12  #       Format and display the menu
13  if [[ $(basename "${arg}X") = "${arg}X" ]] ;then arg="$wd/${arg}"; fi # Force absolute path if relitive
14  echo -e "\n\t\tSubdirectories relative to ${arg}: \n"
15  j=1; for i; do echo -e "$j\t$i"; j=(expr $j + 1); done | pr -r -t -4 -e3 
16  echo -e "\n\t\tEnter the number of your choice -- \c "
17  #       Convert user-input to directory-name and cd to it
18  read -r choice; echo
19  dir=(eval "(echo $\{\"$choice\"\})")        #       Magic here.
20  [ "$choice" -a "$choice" -ge 1 -a "$choice" -le "$#" ] && cd "${arg}"/"$(eval echo "${dir}")" || exit 1
                                                                                      ^SC2128 Expanding an array without an index only gives the first element.
21  }

あなたの提案をコードに組み込み、それを機能させたら、ここに投稿し、質問に回答済みとしてマークします。親切なお力添えありがとうございます。

于 2015-07-29T16:32:54.077 に答える
0

以下のd関数の基礎として、あなたが親切に書いたコードを使用しました。いくつかの小さな問題がありますが、私が望むことはほとんどありません。

  1. スペース文字を含むすべてのサブディレクトリ名は文字で囲まれていますが、そうでないものはそうではありません。

  2. SINGLE QUOTE 文字を含むすべてのサブディレクトリ名は、その文字がバックスラッシュ文字でエスケープされています。

上記の12が問題を引き起こさないことを考えると、それらは受け入れられますが、理想的ではありません。

  1. ユーザー入力がcdを実行した後、サブディレクトリ名のメニューが再びループされます。これは機能と見なすことができると思います。cdコマンドに続くコードのセクションで、ブレーキコマンドをreturnに置き換えようとしましたが、その後のループ メニューを克服できませんでした。

  2. 「。」の包含。サブディレクトリのメニューの先頭にある「..」は理想的ではなく、実際には何の役にも立ちません。

------------------- コードの始まり ------------------------------ -

d() {
    if [ "$BASH" ] && [ "$BASH" != "/bin/sh" ]; then
       echo "$FUNCNAME: ksh only";return 1
    fi

    FIGNORE= # ksh93 equivalent to bash shopt -s dotglob


    if [ ${#} -gt 0 ] ;then             # Only one command line argument accepted
      cd -- "$1" && return 0
    fi

    if [ `ls -AF1|grep /|wc -l` -eq 1 ] ;then       # cd if only one subdirectory
      cd -- `ls -AF1|grep /` && return 0
    fi

  destdir=$(
    while :; do
      subdirs=( ~(N)*/ ) # ksh93 equivalent to subdirs=( */ ) with shopt -s nullglob
      (( ${#subdirs[@]} > 2 )) || break # . and .. are two entries

      echo -e "\n\t\tSubdirectories below ${PWD}: \n" >&2

      for idx in "${!subdirs[@]}"; do
        printf '%d) %q\n' "$idx" "${subdirs[$idx]%/}" >&2
      done

      printf '\nSelect a subdirectory: ' >&2
      read -r
      if [[ $REPLY ]]; then
        cd -- "${subdirs[$REPLY]}" || break     # Continue to loop through subdirectories after cding
      else
        break
      fi
    done
    printf '%s\n' "$PWD"
  )

--------------------------- コードの終了 ---------------------- ---------------

全体として、私は非常に満足しており、このような熟達した Unix ウィザードから知識豊富な支援を受けられたことを非常に幸運に思っています。感謝してもしきれません。

于 2015-08-01T20:14:00.230 に答える