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

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

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

文章目录
  • 前言
  • 最终解决方案
    • 代码
    • 看起来像这样
    • 使用方式
      • 获取用户选择的文件/文件夹
      • 我怎么知道用户选择的是文件还是文件夹
    • 我可不可以在C等语言调用这个脚本啊

前言

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

最终解决方案 代码

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

#!/bin/bash

ERROR_CD=1		# 文件夹无法进入

ENTER_LABEL="选择文件/进入文件夹"
DONE_LABEL="选择当前文件夹"
title="浏览"
TIP="当前路径: "

tmpfile=$(mktemp)

function show()
{
	local init_dir=$(realpath "$1")
	if ! cd "$init_dir"; then
		return $ERROR_CD
	fi
	local list=$(ls -aQ)	# -a 显示隐藏文件, -Q 每个文件左右两边添加双引号并转义特殊字符
	local old_IFS=$IFS
	IFS=$'n'
	listarr=($list)	# 按换行符分割
	IFS=$old_IFS
	list=''
	for i in ${!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}' 0 0 0 $list 2>'$tmpfile'"
	return 0
}

function next_action()
{
	local item=$1
	if [ "$item" == "" ]; then
		# 选择了当前文件夹, 直接输出当前路径到缓存文件
		echo "$(pwd)" >"$tmpfile"
		return 0
	fi
	local typ=$(ls -ld "$item" | cut -c 1)
	if [ "$typ" == "d" ]; then
		# 是目录, 进入
		browse_dir "$item"
	elif [ "$typ" == "l" ]; then
		# 是符号链接, 判断链接到的文件是目录还是其他
		local lnk=$(readlink "$item")
		if ! cd "$(dirname "$lnk")"; then
			return $ERROR_CD
		fi
		next_action "$(basename "$lnk")"
	else
		# 其他当普通文件处理, 文件名输出到缓存文件
		echo "$(realpath "$item")" >"$tmpfile"
	fi
}

function browse_dir()
{
	local status
	local init_dir=$1
	show "$init_dir"
	status=$?
	if [ $status -ne 0 ]; then
		return $status
	fi
	local item=$(cat "$tmpfile")
	next_action "$item"
}

INIT_DIR=${1:-./}

browse_dir "$INIT_DIR"
status=$?
if [ $status -ne 0 ]; then
	exit $status
fi
result=$(cat "$tmpfile")
rm -f "$tmpfile"
echo "$result" >&2
exit 0
看起来像这样

注:不同终端工具下显示的效果是不一样的。

使用方式

  假设上述代码保存到browse_dir.sh,并且已经添加可执行权限。

./browse_dir.sh

  如上即可显示一个文件对话框,初始路径为当前路径。
  如果需要设置初始路径,可以在参数指定,如:

./browse_dir.sh /home	# 初始路径设置为 /home
获取用户选择的文件/文件夹

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

tmpfile=$(mktemp)
./browse_dir.sh / 2>$tmpfile
cat $tmpfile
rm -f $tmpfile

  输出:

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

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

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

  如果输出d表示用户选择的是文件夹,输出-表示用户选择的是文件。如:

  如上输出了-,所以表示是文件。

  如上输出了d,所以是文件夹。

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

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

#include 
#include 

int main()
{
	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, "你选择了: %sn", 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);
	return 0;
}

  如果想把脚本直接放到C代码里也可以这样写:

#include 
#include 
#include 

char bash_script_data[4096];
char *browse_dir(const char *init_dir, const char *output)
{
	strcpy(bash_script_data, "#!/bin/bashn"
	"ERROR_CD=1n"
	"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"; thenn"
	"		return $ERROR_CDn"
	"	fin"
	"	local list=$(ls -aQ)n"
	"	local old_IFS=$IFSn"
	"	IFS=$'\n'n"
	"	listarr=($list)n"
	"	IFS=$old_IFSn"
	"	list=''n"
	"	for i in ${!listarr[*]}; don"
	"		list="$list ${listarr[$i]} \"$(eval "date -d @\$(stat ${listarr[$i]} -c %Y) '+%Y-%m-%d %T'")    $(eval "stat ${listarr[$i]} -c %F")\""n"
	"	donen"
	"	eval "dialog --ok-label '$ENTER_LABEL' --cancel-label '$DONE_LABEL' --title '$TITLE' --menu '${TIP}${init_dir}' 0 0 0 $list 2>'$tmpfile'"n"
	"	return 0n"
	"}n"
	"function next_action()n"
	"{n"
	"	local item=$1n"
	"	if [ "$item" == "" ]; thenn"
	"		echo "$(pwd)" >"$tmpfile"n"
	"		return 0n"
	"	fin"
	"	local typ=$(ls -ld "$item" | cut -c 1)n"
	"	if [ "$typ" == "d" ]; thenn"
	"		browse_dir "$item"n"
	"	elif [ "$typ" == "l" ]; thenn"
	"		local lnk=$(readlink "$item")n"
	"		if ! cd "$(dirname "$lnk")"; thenn"
	"			return $ERROR_CDn"
	"		fin"
	"		next_action "$(basename "$lnk")"n"
	"	elsen"
	"		echo "$(realpath "$item")" >"$tmpfile"n"
	"	fin"
	"}n"
	"function browse_dir()n"
	"{n"
	"	local statusn"
	"	local init_dir=$1n"
	"	show "$init_dir"n"
	"	status=$?n"
	"	if [ $status -ne 0 ]; thenn"
	"		return $statusn"
	"	fin"
	"	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 ]; thenn"
	"	exit $statusn"
	"fin"
	"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;
}

int main()
{
	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, "你选择了: %sn", 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);
	return 0;
}

  输出:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5693880.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存