我正在编写一个 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
鲍勃答案 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 函数的基础。它几乎可以做我想要的,有一些小问题:
包含SPACE字符的所有子目录名称都由字符包围,但那些不包含字符的名称包围。
包含SINGLE QUOTE字符的所有子目录名称都使用BACKSLASH字符转义该字符。
鉴于上面的 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"
)
---------------------------代码结束------------------ ------------------
所以,总的来说,我很高兴,并且非常幸运地获得了这样一个有成就的Unix向导的知识渊博的帮助。我不能够感谢你。