Shell 使用“设置外壳位置参数”;设置ls-AF“;
我正在编写一个ksh函数(放在.profile文件中),它将显示一系列子目录,并允许用户选择一个要刻录到其中的目录。代码如下: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/
# 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函数的基础。它基本上符合我的要求,但有几个小问题:
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行找到:扩展一个没有索引的数组只会得到第一个元素。哦,它也不能显示以点开头的目录名。