gpt4 book ai didi

bash - 如何在 bash 中正确处理和打印带空格的文件

转载 作者:行者123 更新时间:2023-11-29 09:32:00 24 4
gpt4 key购买 nike

我正在用 bash 编写一个简单的递归 ls 程序(我在这方面经验不足,所以尽管粗暴一点)。

该程序应该在单独的行上打印出每个文件(可能是目录),并且每次输入一个新目录时,输出都会移动 4 个空格,以提供类似树的输出。

目前,它不能正确打印出带空格的文件,也不能在目录后加上正斜杠。 (下面有更多详细信息。)

代码

recls () {

# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=`getAbsolutePath "$@"`
# check if it exists
if [ ! -e $argdir ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d $argdir ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal $argdir
return 0

}

recls_internal () {

for file in $@; do
echo -n "$tab${file##/*/}"
if [ -d $file ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
myls_internal $file/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done

}

getAbsolutePath () {

if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi

}

输出

该脚本包含在名为 bash-practice 的文件夹中。当我执行 recls . 时,我得到以下输出:

./
myls.sh
myls.sh~
recdir.sh
recls.sh
recls.sh~
sample
document.txt
sample-folder
sample-stuff
test-12.txt
test-1.txt
test-2.txt
sort-test.txt
sort-text-copy.txt
test-5-19-14-1

问题

如您所见,缩进工作正常,但存在两个问题:

1) 文件 sample document.txt 分两行,因为其中有一个空格。

2) 每个目录前面都应该有一个正斜杠,但出于某种原因,它只适用于第一个目录。

尝试的解决方案

为了修复 (1),我尝试保存内部文件分隔符并将其替换为换行符,如下所示:

...
tab=""
savedIFS=$IFS
IFS="\n"
recls_internal $argdir
IFS=$savedIFS
return 0

但这根本不起作用。它甚至只显示第一个文件夹。显然我对事物的理解是不正确的。

至于 (2),我看不出它不能按预期工作的任何原因。

结论

bash 对我来说很难,因为它似乎比大多数其他编程语言(作为 shell 脚本语言)有更多不寻常的语法,所以我很感激任何对我的错误的见解以及解决方案。

更新#1

我去了网站http://www.shellcheck.com mklement0 建议的,它的提示基本上都是双引号。当我双引号 "$@" 时,程序正确地打印了文件 sample document.txt,但紧接着,它给了我一个 "binary operator预期的”错误。这是打印出来的现在的样子:

enter image description here

更新 #2 [问题解决了吗?]

好吧,事实证明我有一个拼写错误导致它在递归时默认为我的函数的早期版本 myls_internal 。这个早期版本没有用正斜杠标记目录。 “更新”部分中的错误消息也已修复。我换了行

myls_internal "$file/*"

recls_internal $file/*

现在它似乎可以正常工作了。如果有人正在写答案,我仍然感谢您的见解,因为我不太了解引用“$@”如何解决间距问题的机制。

固定代码:

recls () {

# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=$(getAbsolutePath "$@")
# check if it exists
if [ ! -e $argdir ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d $argdir ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal $argdir
return 0

}

recls_internal () {

for file in "$@"; do
echo -n "$tab${file##/*/}"
if [ -d "$file" ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
recls_internal $file/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done

}

getAbsolutePath () {

if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi

}

固定输出:

enter image description here

更新#3

线

recls_internal $file/*

应该是

recls_internal "$file"/*

正确处理其中包含空格的目录。否则,包含 Homework1.pdfHomework2.pdf 的文件夹(例如 cs 350)将展开为

cs 350/Homework1.pdf 350/Homework2.pdf

应该是什么时候

cs 350/Homework1.pdf cs 350/Homework2.pdf

我觉得?我并没有真正了解正在发生的事情的更详细信息,但这似乎可以解决问题。

最佳答案

为了说明"$@"$@ 之间的区别,让我们考虑以下两个函数:

f() { for i in $@; do echo $i; done; }

g() { for i in "$@"; do echo $i; done; }

当使用参数a "b c""d e" 调用这些函数时,结果将是

  • 函数f


f a "b c""d e"
A
b
C
d
电子

  • 函数g
    g a "b c""d e"
    A
    乙丙

因此当“$@”在双引号内时,扩展将每个参数保持在一个单独的词中(即使参数包含一个或多个空格)。$@(不带双引号)展开时,带空格的参数会被认为是两个词。

在您的脚本中,您还需要用双引号将 argdirfile 括起来。当目录或文件的名称包含空格时它很有用,因此名称将被视为单个值。下面你的脚本修改了。

#! /bin/bash -u
recls () {

# store current working directory
# issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling
cwd=$PWD
# get absolute path of arg
argdir=`getAbsolutePath "$@"`
# check if it exists
if [ ! -e "$argdir" ]; then
echo "$argdir does not exist"
return 1
fi
echo "$argdir exists"
# check if it's a directory
if [ ! -d "$argdir" ]; then
echo "$argdir is not a directory"
return 2
fi
echo "$argdir is a directory"
tab=""
recls_internal "$argdir"
return 0

}

recls_internal () {

for file in "$@"; do
echo -n "$tab${file##/*/}"
if [ -d "$file" ]; then
# print forward slash to show it's a directory
echo "/"
savedtab=$tab
tab="$tab "
recls_internal "$file"/*
tab=$savedtab
else
# if not a directory, print a new line
echo ""
fi
done

}

getAbsolutePath () {

if [ -z ${1##/*} ]; then
echo "$1"
else
echo "$cwd/$1"
fi

}

关于bash - 如何在 bash 中正确处理和打印带空格的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23767332/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com