设置Shell位置参数用"设置ls -AF"

时间:2015-07-27 19:12:37

标签: shell set ksh ifs

我正在编写一个 ksh 函数(放在 .profile 文件中),该函数将显示一个子目录菜单,并允许用户选择一个子目录。 CD 。这是代码:

# 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"`
}

除了包含 space 字符的目录名外,此函数运行良好。如果目录名称包含 space ,则 set 命令将目录名称的每个空格分隔元素(而不是完整的目录名称)设置为单独的位置参数;这在这里没用。

我试图设置 $ IFS shell变量(其中包含空间标签换行符默认情况下)为单个换行符字符:

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

这似乎可以通过以下方式实现目标:

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

但是尽管我付出了最大的努力(在几天的工作中),我未能将包含空格的整个目录名称设置为位置参数的值。

我错过了什么?

特此征求意见并欢迎。

ADVAthanksNCE

鲍勃

3 个答案:

答案 0 :(得分:1)

简短回答:你做不到。别试试。请参阅the ParsingLs页面,了解为什么编程使用-F本身就容易出错。

如果没有在shell中自己实现(这确实可行),你就无法获得set -- */ 行为,但以下是正确的方式将子目录列表放入参数列表:

/

如果您不希望在每个条目的末尾都有文字set -- */ # put list of subdirectories into "$@" set -- "${@%/}" # strip trailing / off each

eval

但更好的是:使用数组以避免以后需要dirs=( */ ) dirs=( "${dirs[@]%/}" ) printf '%s\n' "${dirs[$choice]}" # emit entry at position $choice 魔法。

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

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

      printf '\nSelect a subdirectory: ' >&2
      read -r choice
      if [[ $choice ]]; then
        cd -- "${subdirs[$choice]}" || break
      else
        break
      fi
    done
    printf '%s\n' "$PWD"
  )
  [[ $destdir ]] && cd -- "$destdir"
}

让我们将这一切联系在一起:

if (filename.Contains(" "))
{
    filename= filename.Replace(" ", Uri.HexEscape(' '));
}

答案 1 :(得分:0)

虽然仍然无效,但该版本确实传递了 shellcheck ,但有一个例外:

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  }

我将您的建议合并到代码中并使其正常运行后,我会在此处发布,并标记我的问题。谢谢你的帮助。

答案 2 :(得分:0)

我使用了您编写的代码作为下面 d 函数的基础。它几乎可以做我想要的,有一些小问题:

  1. 包含SPACE字符的所有子目录名称都由字符包围,但那些不包含字符的名称包围。

  2. 包含SINGLE QUOTE字符的所有子目录名称都使用BACKSLASH字符转义该字符。

  3. 鉴于上面的 1 2 没有问题,可以接受,但不理想。

    1. 用户输入 cd 后,子目录名称菜单再次循环播放。我想这可以被认为是一个特征。我尝试在 cd 命令之后的代码部分中用 return 替换 brake 命令,但是在克服后续循环菜单时失败了。

    2. 包含“。”子目录菜单头部的“..”并不理想,实际上没有任何好处。

    3. -------------------代码开始-------------------------- ----

      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向导的知识渊博的帮助。我不能够感谢你。