繁体   English   中英

处理 bash 脚本中的特殊字符

[英]Handling special characters in bash script

我不熟悉 bash 脚本。 也许这是一个愚蠢的问题。 但我找不到答案。 我正在研究一个 bash 脚本,它模仿命令ls -sh的行为,但实际上使用du -sh来获取文件和文件夹大小。 它对 output 进行排序。 很像du -sh* | sort -h 使用 colors du -sh* | sort -h

#!/usr/bin/bash

if [ "$#" = "0" ]
then
    du -sh *|awk -f /path/to/color-ls.awk|sort -h
else
    du -sh $@|awk -f /path/to/color-ls.awk|sort -h
fi

其中ls-color.awk是:

# color-ls.awk
size=$1;
name=$2;
for (i=3; i<=NF; i++)
{
    tmp=(name " " $i);
    name=tmp
}
# filename=($0 ~ /'/)? ("\"" name "\""):("'" name "'")
filename=("'" name "'")
printf $1 " "
cmd=("ls -d " filename " --color")
system(cmd)

使用ls --color为 du -sh 的 output 着色的 awk 脚本

我的脚本适用于大多数文件名,甚至包含空格的文件名。 但它有一些涉及特殊字符的问题,我不知道如何解决。

1. 在没有 arguments 的情况下运行:

它正在解释任何包含导致错误的单引号的文件名

sh: 1: Syntax error: Unterminated quoted string

2. 使用 arguments 运行时:

与没有 arguments 的问题相同。 并且它将带有空格的文件名解释为两个名称。

示例:当在名为VirtualBox VMs的文件夹上使用时,或者在我的主目录中将*作为参数时,它是 output:

du: cannot access 'VirtualBox': No such file or directory
du: cannot access 'VMs': No such file or directory

3. 我想要的:

我希望脚本跳过特殊字符并将它们按原样传递给du

4.我尝试了什么:

我尝试在每个文件名之前和之后添加双引号

parse(){
    for arg in $@
    do
        printf "\"$arg\"\n"
    done
}

但它似乎没有用。 du 不接受附加到文件名的引号。

du: cannot access '"VirtualBox': No such file or directory
du: cannot access 'VMs"': No such file or directory

此外,用\'替换引号对以太没有帮助。 也许我只是做错了。

# du -sh $(printf "file'name\n" |sed "s/'/\\\'/g")
du: cannot access 'file\'\''name': No such file or directory
# ls file\'name 
"file'name"

空间也是如此

du: cannot access 'VirtualBox\': No such file or directory
du: cannot access 'VMs': No such file or directory

5. 额外:

我想让脚本像正常的ls -sh一样工作,但使用排序的 output 并且在文件夹方面具有更准确的结果。 但是当向它提供 arguments 时,此脚本的工作方式与ls -sh -d类似。 使lh Desktop显示 Desktop 的大小,而不是 Desktop 中单个文件和文件夹的大小。 我相信这可以通过一个循环来解决,该循环检查每个参数是文件还是文件夹并相应地执行du -sh然后排序。

#!/usr/bin/bash

if [ "$#" = "0" ]
then
    du -sh *|awk -f /path/to/color-ls.awk|sort -h
else
    for i in $@
    do
        if [[ -d "$i" ]]; then
            du -sh $i/* |awk -f /path/to/color-ls.awk
        else
            du -sh "$i" |awk -f /path/to/color-ls.awk
        fi
    done|sort -h
fi

但由于某种原因它不起作用

# lh Desktop/
du: cannot access 'Desktop/*': No such file or directory

而使用du -sh Desktop/*通常适用于交互式 shell。

提前致谢。

由于您没有包含shopt -s nullglob ,因此Desktop/*很可能没有扩展到任何奇怪的文件,除非那里确实没有文件,您在交互模式下启用了nullglob ,而du -sh没有实际显示Desktop中文件的大小。

您也可能在Desktop/不存在的地方调用脚本。

您可以添加一个打印$PWD的调试语句。 您也可以尝试使用bash -x运行脚本。

在您的脚本中,我建议启用nullglob然后对其进行修改,以便如果目标目录不包含任何文件,则不会调用du -sh

就像是:

set -- "$i"/*; [[ $# -gt 0 ]] && du -sh -- "$@" ...

扩展时还应引用$@

for i in "$@"; do

这可以简化为for i; do for i; do ,但我们将修改循环内的位置参数,因此我们展开"$@"

您也可以选择将展开的文件存储在数组中。

请不要在一个问题上发表这么多。 请每个问题一个问题。 每个问题一个脚本,等等。

确保使用 shellcheck 检查您的脚本 它会抓住你的错误。 请参阅https://mywiki.wooledge.org/Quotes

  1. 在没有 arguments 的情况下运行时:

awk 脚本中的filename=("'" name "'")是一种将带有'引号的任何内容传递给system()调用的无效方法,因此正如预期的那样,您会遇到 unterminated '错误。 修复脚本,或者在 Bash 中更好地重写它,不需要 awk,可能在 Python 或 Z014344AD06FEDA73E。

  1. 使用 arguments 运行时:

$@经历了分词文件名扩展(你应该研究的主题),并将输入的词分词成空格上的词。 使用"$@" 引用扩展。

  1. 我想要的是:

您将使用"$@"来执行此操作

  1. 我尝试了什么:

可变内容无关紧要。 你必须改变你使用变量的方式,而不是它的内容。 即使用引号。

  1. 额外的:

你没有引用扩展。 使用"$i"而不是$i 它是"$i"/*

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM