如何通过命令行提示用户使用GUI对话框选择文件/目录路径?

假设我有一个像这样的脚本:
(该示例描述了一个rsync使用案例)
#!/bin/bash
echo -n "Enter Source Directory:"
read srcdir
echo -n "Enter Destination Directory:"
read dstdir
rsync -av --delete "$srcdir" "$dstdir"

这里的想法是提示用户输入rsync要使用的“源”和“目标”目录。目前,用户必须通过命令行手动输入 /path/to/directory/相反地,我希望通过图形用户界面(GUI)来提示用户输入路径。 类似于这样: screem
有哪些命令可以用来提示用户使用图形界面选择窗口,并将文件路径返回到命令行?

2你可以使用Zenity: https://help.gnome.org/users/zenity/stable/file-selection.html.en - TuKsn
4请记得添加关于GUI窗口使用的警告。不必要的弹出窗口可能会引起高级用户的愤怒。 - mike3996
5为什么,哦为什么你会想要实现这样一个让人烦恼的“功能”呢?记住,如果我们在命令行中输入目录,我们可以使用Tab键自动补全,而不需要等待某个图形界面加载。为什么有人会想要将图形界面添加到一个完全正常的Shell脚本中,我真是无法理解。 - terdon
1既然我们正在混合范式,为什么不让用户通过网络应用程序输入路径呢? - Tulains Córdova
4@terdon 因为如果我们直接运行脚本而不是在终端中运行,我想要提供一个图形用户界面窗口。 - Pandya
有没有办法判断脚本是在终端还是直接运行的?或许可以使用类似isatty()这样的函数来实现吗? - user423626
4个回答

你可以用这个来处理文件:
zenity --file-selection

这是给文件夹的。
zenity --file-selection --directory

使用方法:

运行以下命令:
zenity --help-general
zenity --help-file-selection

通常它与当前的主题相匹配(至少对于GTK窗口管理器来说),在我使用修改版Zukitwo 3.8的机器上,它看起来是这样的: 一种使用它的方式是这样的:
echo "you selected $(zenity --file-selection)"

这将导致你选择了 /path/to/file。
你还可以使用选项来设置一个合适的标题和起始目录 - 例如,在你的 rsync 使用情况下:
zenity --file-selection --directory --title="Choose rsync source directory" --filename=$HOME/Desktop/

对于文件,您还可以指定文件类型进行选择 - 例如:
zenity --file-selection --file-filter='PDF files (pdf) | *.pdf' --title="Select a PDF file"

注意:您还可以使用YAD,这是Zenity的一个分支,具有更多功能。
sudo add-apt-repository ppa:webupd8team/y-ppa-manager
sudo apt-get update
sudo apt-get install yad

来源

大部分情况下,你可以以相同的方式使用它 - 用于文件浏览器:

yad --file-selection

为了帮助页面:
yad --help-all

尽管在当时(大约版本26?),它还没有更新以适应新的GTK 3.14+界面(zenity已经更新了)- 它具有更多功能,但请检查兼容性(根据文档,它应该适用于GTK+ >= 2.16.0)。

2Yad是Zenity的一种显著增强版本,并且在Zenity项目停滞后,已经在很大程度上取而代之。我看到Zenity现在在Gnome.org上重新开发(只适用于Gnome3?),但我没有找到下载它的方法。 - DocSalvager
@DocSalvage - 那个页面相当古老了 - 上面写着下一个版本是“3.2” - 我在一个相当旧的 Fedora 19 系统上有 3.8 版本(带有 Gnome 3.8 - Gnome 的许多部分都会为每个 Gnome shell 版本进行更新(所以它可能已经更新到了 3.10 + 3.12))。它最后处理的是 2005-2009 年的错误报告。你可以从 Ubuntu 软件仓库中获取最新稳定版(再次是 3.8)- http://packages.ubuntu.com/trusty/zenity。你还可以在这里找到 Yad 的编译版本 here - Wilf
Yad看起来相当不错 - 它比zenity有更多的选项 :) - Wilf
1@Wilf 是的,yad就像是强化版的Zenity。一旦你掌握了它,它会让你感到非常灵活和强大。我已经成为了它的忠实拥护者。顺便说一句,我在下面对原帖的问题进行了回答(抱歉,我忍不住要加个梗)。 - Scooby-2
@Scooby-2酷!将安装说明添加到答案中(这样将来的用户就不必进行评论了)。 - Wilf
@Wilf 想得真好。顺便说一下,我正在运行 Mint 17,yad 也可以从软件中心安装。不过我不知道它是否适用于其他版本。 - Scooby-2
@Scooby-2,似乎在Ubuntu软件仓库中找不到(http://packages.ubuntu.com/search?suite=all&exact=1&searchon=names&keywords=yad)同样,在mint qiana的默认仓库中也没有。你可能过去添加了PPA,因为WebUp8上几乎所有的东西都使用它(或者我只是个白痴 :) - Wilf
@Wilf 我的 /etc/apt/sources.list 中只有 virtualbox 这一项。我不知道如何检查它是从哪里安装的,但我想我只需要输入 sudo apt-get install yad。顺便说一下,在软件管理器中也显示了它,并列出了版本号:0.27.0-1webupd8utopic0。另外,很抱歉回复晚了。 - Scooby-2

只是为了记录,您可以使用 dialog 来实现基于文本的用户界面(TUI)解决方案。

语法:

dialog --title "text" --fselect /path/to/dir height width

例子:

FILE=$(dialog --stdout --title "Please choose a file" --fselect $HOME/ 14 48)
echo "${FILE} file chosen."

输出将会是这样的:

Example

正如@Wilf所指出的那样,您可以使用$LINES和$COLUMNS变量来使其填充终端。
$(dialog --stdout --title "Please choose a file" --fselect $HOME/ $(expr $LINES - 15) $(expr $COLUMNS - 10))

1虽然这是一个正确的替代方案,但它并没有像问题中提到的那样提供图形用户界面窗口! - Pandya
3我知道,但可能有其他人会发现它有用。我发布了截图以避免任何混淆。 - kraxor
11而且,公平地说,依我个人的看法,它可以算作一个图形用户界面。 - kraxor
3图形用户界面(GUIs)和文本用户界面(TUIs)之间常用的界限是“原子”的大小:它是一个像素还是一个字符? - mike3996
@progo 感谢你的解释,我已经相应地编辑了我的回答。 - kraxor
3好答案-某些终端的宽度和高度是由变量$LINES$COLUMNS定义的-因此您可以运行 $(dialog --stdout --title "请选择一个文件" --fselect $HOME/ $(expr $LINES - 15) $(expr $COLUMNS - 10)) 来使其填充终端/屏幕窗口。 - Wilf
@Wilf 谢谢,我已经将你的信息添加到答案中。 - kraxor
哇,真棒!你怎样使用这个来仅选择目录呢? - tatsu

我知道这已经是8个月前的问题,而且OP的问题已经得到了回答。然而,虽然提到了yad,但没有给出示例。下面是我使用yad的解决方案。
DIR="/home" \
i=0;for location in source destination
do
((i++));selection[$i]=$(yad --center \
--width 350 \
--form \
--title="yad example" \
--text="Select $location directory" \
--field=:LBL "" \
--field=Path:DIR "$DIR" \
--separator='' )
done;\
echo "Command to run is \"rsync -av --delete ${selection[1]} ${selection[2]}\""

这是它的工作方式。我们将yad放在一个for循环中,第一次设置变量$locationsource,第二次设置为destination。输出结果放在数组selection[]中,其中变量i用作索引。开始时,它被设置为0,并且每次循环都会递增。因此,源保存为${selection[1]},目标保存为${selection[2]}
第一行的DIR="/home"设置了对话框的默认值。可以通过在终端中输入yad --help来查找yad命令选项。

yad screenshot


这是答案的最短(也是最好)解决方案:Yad 提供了与 zenity 类似的精确选项。
yad --file-selection --directory

这将打开一个目录选择对话框。 如果没有额外的参数--directory,它将变成一个文件选择对话框。