Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 使用“设置外壳位置参数”;设置ls-AF“;_Shell_Set_Ksh_Ifs - Fatal编程技术网

Shell 使用“设置外壳位置参数”;设置ls-AF“;

Shell 使用“设置外壳位置参数”;设置ls-AF“;,shell,set,ksh,ifs,Shell,Set,Ksh,Ifs,我正在编写一个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/

我正在编写一个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 shell变量(默认情况下包含空格、制表符和换行符)设置为一个换行符,并带有:

IFS=`echo`        # echo outputs a trailing newline character by default
这似乎实现了预期目标,通过以下方式进行验证:

echo -e "$IFS\c" | hexdump -c
但是,尽管我尽了最大努力(在几天的工作过程中),我还是未能将包含空格的整个目录名设置为位置参数的值

我错过了什么

特此征求意见,欢迎提出建议

ADVAthanksNCE


鲍勃

简短的回答:你不能那样做。不要尝试。请参阅第页,了解为什么编程使用
ls
天生容易出错


如果不在shell中自己实现它,就无法获得
-F
行为(这确实是可行的),但下面是将子目录列表放入参数列表的正确方法:

set -- */
如果您不希望在每个条目的末尾都有一个文本
/

set -- */       # put list of subdirectories into "$@"
set -- "${@%/}" # strip trailing / off each

不过更好的是:使用数组避免以后需要
eval
magic

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

尽管仍不工作,但此版本确实通过了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  }

一旦我将你的建议融入到代码中,并使其功能化,我将在这里发布它,并标记我的问题是否得到了回答。感谢您的帮助。

我已经使用了您编写的代码作为下面d函数的基础。它基本上符合我的要求,但有几个小问题:

  • 所有包含空格字符的子目录名称都由字符包围,但不包含空格字符的子目录名称则不是

  • 所有包含单引号字符的子目录名称都使用反斜杠字符转义该字符

  • 考虑到上述1和2不会导致任何问题,它们是可以接受的,但并不理想

  • 在用户输入完成cd之后,子目录名称的菜单再次循环。我想这可能是一个特点。我尝试在cd命令之后的代码段中用return替换brake命令,但未能成功克服随后的循环菜单

  • 在子目录菜单的开头包含“.”和“.”是不理想的,实际上也没有什么用处

  • -------------------代码开始------------------------------

    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"
      )
    
    ---------------------------代码结束------------------------------------

    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"
      )
    

    <> P>所以,总体而言,我非常高兴,并且认为我非常幸运地收到了这样一个完成的UNIX向导的知识帮助。非常感谢您的帮助。

    非常感谢您的这项技术。它的工作非常出色!关于解析ls,这里似乎是对您善意提供的指针的反驳:。在接受这个问题的答案之前,我将发布一个包含您善意建议的工作版本。现在,这里有一个新版本的D函数,它通过SHILCHECK:[不幸的是,由于字符计数StAdExchange对评论的限制,我无法发布该代码。]您可能会考虑将您自己的答案用代码来讨论。这是我第一次使用StExchange,我不知道该怎么做。啊,我看到了这一页底部的方框……评论不是为了进一步讨论;这段对话已经结束。
    函数
    格式不好,在POSIX sh中不存在——请改用
    d(){
    。我在这个问题上直接给出了很多评论(现在改为聊天),这些评论在这段代码中没有被考虑。(顺便说一句,我之前误解了——当建议“添加答案”按钮时,我认为您实际上有一个想要发布的工作答案)。我真诚地感谢您的示例代码答案。它似乎与预期一样工作,但有一些例外。1.它在目录名的空格字符前放置了一个反斜杠。2.目录菜单垂直显示。而这将适应长目录名(这很有用),它限制了选项菜单可能包含的目录名的数量,而无需在屏幕外滚动。您的代码简洁优雅,我非常感谢您的睿智帮助。顺便说一句,shellcheck在第6行找到:扩展一个没有索引的数组只会得到第一个元素。哦,它也不能显示以点开头的目录名。