Linux bash 命令行下实现可视化文件或文件夹浏览文章目录
- 前言
- 最终解决方案
- 代码
- 看起来像这样
- 使用方式
- 获取用户选择的文件/文件夹
- 我怎么知道用户选择的是文件还是文件夹
- 我可不可以在C等语言调用这个脚本啊
前言
有时候部署环境,需要配置文件路径或者载入相应的配置文件。这种情况下,如果用传统的手动修改配置的方式配置,会比较容易出意外(比如中文符号和英文符号混淆、大小写错误、l和i混淆等)。
这个时候,我解决的方式就是模仿Windows下常见的文件对话框,在下载文件、打开文件时Windows常见的文件对话框。与Windows不同的是,我要在命令行界面下使用图形化的对话框。写库是不可能写库的,我着急着用这个功能,所以就直接用了现成的dialog工具来完成。
最终解决方案
代码
因为我是在部署环境的场景下使用,所以就不用C或C++写这个代码了,使用bash代码。依赖dialog,可以使用sudo yum install dialog
或sudo apt-get install dialog
安装dialog。
#!/bin/bashERROR_CD=1ENTER_LABEL="选择文件/进入文件夹"DONE_LABEL="选择当前文件夹"TITLE="浏览"TIP="当前路径: "tmpfile=$(mktemp)functionshow(){localinit_dir=$(realpath"$1")if!cd"$init_dir";thenreturn$ERROR_CDfilocallist=$(ls -aQ)localold_IFS=$IFSIFS=$'\n'listarr=($list)IFS=$old_IFSlist=''foriin${!listarr[*]};dolist="$list${listarr[$i]}\"$(eval "date -d @\$(stat ${listarr[$i]} -c %Y) '+%Y-%m-%d %T'")$(eval"stat${listarr[$i]} -c %F")\""
done
eval "dialog --ok-label'$ENTER_LABEL' --cancel-label'$DONE_LABEL' --title'$TITLE' --menu'${TIP}${init_dir}'000$list2>'$tmpfile'"return0}functionnext_action(){localitem=$1if["$item"==""];thenecho"$(pwd)">"$tmpfile"return0filocaltyp=$(ls -ld"$item"|cut -c1)if["$typ"=="d"];then
browse_dir"$item"elif["$typ"=="l"];thenlocallnk=$(readlink"$item")if!cd"$(dirname"$lnk")";thenreturn$ERROR_CDfi
next_action"$(basename"$lnk")"elseecho"$(realpath"$item")">"$tmpfile"fi}functionbrowse_dir(){local statuslocalinit_dir=$1
show"$init_dir"status=$?if[$status -ne0];thenreturn$statusfilocalitem=$(cat"$tmpfile")
next_action"$item"}INIT_DIR=${1:-./}
browse_dir"$INIT_DIR"status=$?if[$status -ne0];thenexit$statusfiresult=$(cat"$tmpfile")rm -f"$tmpfile"echo"$result">&2exit0
看起来像这样
注:不同终端工具下显示的效果是不一样的。
使用方式
假设上述代码保存到browse_dir.sh,并且已经添加可执行权限。
./browse_dir.sh
如上即可显示一个文件对话框,初始路径为当前路径。
如果需要设置初始路径,可以在参数指定,如:
./browse_dir.sh /home
获取用户选择的文件/文件夹
我把用户选择放到了标准错误输出里了,也就是通过重定向标准错误输出到缓存文件,然后读取这个缓存文件就可以获取到用户的选择了。例如:
tmpfile=$(mktemp)
./browse_dir.sh /2>$tmpfilecat$tmpfilerm -f$tmpfile
输出:
我怎么知道用户选择的是文件还是文件夹
要判断用户选择的是文件还是文件夹,需要自行通过命令判断,如:
ls -ld<用户选择的结果>|cut -c1
如果输出d
表示用户选择的是文件夹,输出-
表示用户选择的是文件。如:
如上输出了-,所以表示是文件。
如上输出了d,所以是文件夹。
我可不可以在C等语言调用这个脚本啊
可以,调用的方法很多,如:
#include#includeintmain(){char tmp[11]="tmp.XXXXXX";char cmd[512]={0};char item[261]={0};char typ;
FILE*tmpfile=NULL;int tmpfd=mkstemp(tmp);close(tmpfd);sprintf(cmd,"./browse_dir.sh / 2>%s", tmp);system(cmd);
tmpfile=fopen(tmp,"rb");fread(item,260,1, tmpfile);fclose(tmpfile);strtok(item,"\n");fprintf(stdout,"你选择了: %s\n", item);fprintf(stdout,"它是一个: ");sprintf(cmd,"ls -ld %s | cut -c 1 >%s", item, tmp);system(cmd);
tmpfile=fopen(tmp,"rb");fread(&typ,1,1, tmpfile);fclose(tmpfile);if(typ=='d'){fprintf(stdout,"文件夹\n");}else{fprintf(stdout,"文件\n");}remove(tmp);return0;}
如果想把脚本直接放到C代码里也可以这样写:
#include#include#includechar bash_script_data[4096];char*browse_dir(constchar*init_dir,constchar*output){strcpy(bash_script_data,"#!/bin/bash\n""ERROR_CD=1\n""ENTER_LABEL=\"选择文件/进入文件夹\"\n""DONE_LABEL=\"选择当前文件夹\"\n""TITLE=\"浏览\"\n""TIP=\"当前路径: \"\n""savedir=$(pwd)\n""tmpfile=$(mktemp)\n""function show()\n""{\n"" local init_dir=$(realpath \"$1\")\n"" if ! cd \"$init_dir\"; then\n"" return $ERROR_CD\n"" fi\n"" local list=$(ls -aQ)\n"" local old_IFS=$IFS\n"" IFS=$'\\n'\n"" listarr=($list)\n"" IFS=$old_IFS\n"" list=''\n"" for i in ${!listarr[*]}; do\n"" list=\"$list ${listarr[$i]} \\\"$(eval \"date -d @\\$(stat ${listarr[$i]} -c %Y) '+%Y-%m-%d %T'\") $(eval \"stat ${listarr[$i]} -c %F\")\\\"\"\n"" done\n"" eval \"dialog --ok-label '$ENTER_LABEL' --cancel-label '$DONE_LABEL' --title '$TITLE' --menu '${TIP}${init_dir}' 0 0 0 $list 2>'$tmpfile'\"\n"" return 0\n""}\n""function next_action()\n""{\n"" local item=$1\n"" if [ \"$item\" == \"\" ]; then\n"" echo \"$(pwd)\" >\"$tmpfile\"\n"" return 0\n"" fi\n"" local typ=$(ls -ld \"$item\" | cut -c 1)\n"" if [ \"$typ\" == \"d\" ]; then\n"" browse_dir \"$item\"\n"" elif [ \"$typ\" == \"l\" ]; then\n"" local lnk=$(readlink \"$item\")\n"" if ! cd \"$(dirname \"$lnk\")\"; then\n"" return $ERROR_CD\n"" fi\n"" next_action \"$(basename \"$lnk\")\"\n"" else\n"" echo \"$(realpath \"$item\")\" >\"$tmpfile\"\n"" fi\n""}\n""function browse_dir()\n""{\n"" local status\n"" local init_dir=$1\n"" show \"$init_dir\"\n"" status=$?\n"" if [ $status -ne 0 ]; then\n"" return $status\n"" fi\n"" local item=$(cat \"$tmpfile\")\n"" next_action \"$item\"\n""}\n""INIT_DIR=");strcat(bash_script_data, init_dir);strcat(bash_script_data,"\n""browse_dir \"$INIT_DIR\"\n""status=$?\n""if [ $status -ne 0 ]; then\n"" exit $status\n""fi\n""result=$(cat \"$tmpfile\")\n""rm -f \"$tmpfile\"\n""cd \"$savedir\"\n""echo \"$result\" >");strcat(bash_script_data, output);strcat(bash_script_data,"\n");return bash_script_data;}intmain(){char tmp[11]="tmp.XXXXXX";char cmd[512]={0};char item[261]={0};char typ;
FILE*tmpfile=NULL;int tmpfd=mkstemp(tmp);close(tmpfd);system(browse_dir("/", tmp));
tmpfile=fopen(tmp,"rb");fread(item,260,1, tmpfile);fclose(tmpfile);strtok(item,"\n");fprintf(stdout,"你选择了: %s\n", item);fprintf(stdout,"它是一个: ");sprintf(cmd,"ls -ld %s | cut -c 1 >%s", item, tmp);system(cmd);
tmpfile=fopen(tmp,"rb");fread(&typ,1,1, tmpfile);fclose(tmpfile);if(typ=='d'){fprintf(stdout,"文件夹\n");}else{fprintf(stdout,"文件\n");}remove(tmp);return0;}
输出: