我希望能够运行 bash 脚本,让它列出可能的文件作为选择一个文件的选项,然后通过 scp 将该文件传输到目的地...
scp 部分没问题,但如何获取文件列表并能够选择一个文件对我来说是一个挑战......
$ ./script
Please select a file.
[0] ~/Desktop/ScreenShot-04-06-19-01:02:33.png
[1] ~/Desktop/ScreenShot-04-06-19-01:03:33.png
[2] ~/Desktop/ScreenShot-04-06-19-01:04:33.png
Enter File Index ID:
答案1
另一种方法是使用 bash 中的 select :
$ cat myscript
PS3="Enter File Index ID: "
echo "Please select a file."
select file ; do
[ "$file" ] &&
{
echo "$file"
break
} ||
{
echo "bad choice"
break
}
done
你这样称呼它:
myscript ~/Desktop/*.png
PS:将 script 重命名为 myscript 因为 script 是一个命令。
看man script
答案2
要提供一个交互式菜单,bash
用户可以在其中从多个文件路径名中进行选择,您可能需要使用如下内容:
#!/bin/bash
files=( "$HOME/Desktop/ScreenShot-"*.png )
PS3='Select file to upload, or 0 to exit: '
select file in "${files[@]}"; do
if [[ $REPLY == "0" ]]; then
echo 'Bye!' >&2
exit
elif [[ -z $file ]]; then
echo 'Invalid choice, try again' >&2
else
break
fi
done
# use scp to upload "$file" here
在这里,我们使用bash
语句select
来提供菜单,并使用PS3
三级提示来提供自定义提示。
用户可以退出脚本,而无需通过在0
提示符下输入从列表中选择文件。如果给出无效响应,用户将有另一次选择文件的机会。根据提示按 即可重新显示菜单Enter。
循环内部的逻辑如何select
制定并不那么重要,只要脚本在$REPLY
(用户输入的实际值)为空时终止0
并在$file
(从数组中选取的值)为空时重试即可。另一种select
声明体可能看起来像
if [[ $REPLY == "0" ]]; then
echo 'Bye!' >&2
exit
elif [[ -n $file ]]; then
break
fi
echo 'Invalid choice, try again' >&2
文件名通过 shell glob 插入到命名数组中。您还可以使用以下命令从脚本的命令行获取相关文件
files=( "$@" )
在 POSIX shell 中,您通常无权访问命名数组或select
.相反,你可以做类似的事情
#!/bin/sh
set -- "$HOME/Desktop/ScreenShot-"*.png
while true; do
i=0
for pathname do
i=$(( i + 1 ))
printf '%d) %s\n' "$i" "$pathname" >&2
done
printf 'Select file to upload, or 0 to exit: ' >&2
read -r reply
number=$(printf '%s\n' "$reply" | tr -dc '[:digit:]')
if [ "$number" = "0" ]; then
echo 'Bye!' >&2
exit
elif [ "$number" -gt "$#" ]; then
echo 'Invalid choice, try again' >&2
else
break
fi
done
shift "$(( number - 1 ))"
file=$1
# use scp to upload "$file" here
这是一个相当常见的输入循环,它会进行迭代,直到用户输入有效的条目(或直到0
输入并且脚本退出)。每次输入错误时都会重新显示菜单。
路径名通过 shell glob 被带入位置参数列表中,就像在变bash
体中一样,但菜单是手动打印的,每个输出的菜单条目都有一个递增的整数。
最后的shift
会移走位置参数列表开头的条目,以便$1
成为用户想要上传的路径名。
要改为使用命令行上给出的路径名,只需删除初始set
命令即可。
答案3
这就是我在 bash 脚本中的做法(也可以在 POSIXsh
脚本中使用):
echo 'Please select a file.'
n=0
for img in ~/Desktop/ScreenShot-*.png
do
n=$((n+1))
printf "[%s] %s\n" "$n" "$img"
eval "img${n}=\$img"
done
if [ "$n" -eq 0 ]
then
echo >&2 No images found.
exit
fi
printf 'Enter File Index ID (1 to %s): ' "$n"
read -r num
num=$(printf '%s\n' "$num" | tr -dc '[:digit:]')
if [ "$num" -le 0 ] || [ "$num" -gt "$n" ]
then
echo >&2 Wrong selection.
exit 1
else
eval "IMG=\$img${num}"
echo Selected image is "$IMG"
fi