Linux bash 命令行下实现可视化文件或文件夹浏览

2022-08-24 13:56:22
Linux bash 命令行下实现可视化文件或文件夹浏览

前言

  有时候部署环境,需要配置文件路径或者载入相应的配置文件。这种情况下,如果用传统的手动修改配置的方式配置,会比较容易出意外(比如中文符号和英文符号混淆、大小写错误、l和i混淆等)。
  这个时候,我解决的方式就是模仿Windows下常见的文件对话框,在下载文件、打开文件时Windows常见的文件对话框。与Windows不同的是,我要在命令行界面下使用图形化的对话框。写库是不可能写库的,我着急着用这个功能,所以就直接用了现成的dialog工具来完成。

最终解决方案

代码

  因为我是在部署环境的场景下使用,所以就不用C或C++写这个代码了,使用bash代码。依赖dialog,可以使用sudo yum install dialogsudo apt-get install dialog安装dialog。

#!/bin/bashERROR_CD=1# 文件夹无法进入ENTER_LABEL="选择文件/进入文件夹"DONE_LABEL="选择当前文件夹"TITLE="浏览"TIP="当前路径: "tmpfile=$(mktemp)functionshow(){localinit_dir=$(realpath"$1")if!cd"$init_dir";thenreturn$ERROR_CDfilocallist=$(ls -aQ)# -a 显示隐藏文件, -Q 每个文件左右两边添加双引号并转义特殊字符localold_IFS=$IFSIFS=$'\n'listarr=($list)# 按换行符分割IFS=$old_IFSlist=''foriin${!listarr[*]};do# 每一个文件, 添加修改日期和文件类型信息到右边list="$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"==""];then# 选择了当前文件夹, 直接输出当前路径到缓存文件echo"$(pwd)">"$tmpfile"return0filocaltyp=$(ls -ld"$item"|cut -c1)if["$typ"=="d"];then# 是目录, 进入
		browse_dir"$item"elif["$typ"=="l"];then# 是符号链接, 判断链接到的文件是目录还是其他locallnk=$(readlink"$item")if!cd"$(dirname"$lnk")";thenreturn$ERROR_CDfi
		next_action"$(basename"$lnk")"else# 其他当普通文件处理, 文件名输出到缓存文件echo"$(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# 初始路径设置为 /home

获取用户选择的文件/文件夹

  我把用户选择放到了标准错误输出里了,也就是通过重定向标准错误输出到缓存文件,然后读取这个缓存文件就可以获取到用户的选择了。例如:

tmpfile=$(mktemp)
./browse_dir.sh /2>$tmpfilecat$tmpfilerm -f$tmpfile

  输出:
在这里插入图片描述
在这里插入图片描述

我怎么知道用户选择的是文件还是文件夹

  要判断用户选择的是文件还是文件夹,需要自行通过命令判断,如:

ls -ld<用户选择的结果>|cut -c1

  如果输出d表示用户选择的是文件夹,输出-表示用户选择的是文件。如:
在这里插入图片描述
  如上输出了-,所以表示是文件。
在这里插入图片描述
  如上输出了d,所以是文件夹。

我可不可以在C等语言调用这个脚本啊

  可以,调用的方法很多,如:

#include<stdio.h>#include<stdlib.h>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);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<stdio.h>#include<stdlib.h>#include<string.h>char 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;}

  输出:
在这里插入图片描述

  • 作者:Eyre Turing
  • 原文链接:https://blog.csdn.net/nicedante/article/details/122278802
    更新时间:2022-08-24 13:56:22