在 shell 脚本中,如何在完成一项工作后为变量赋予另一个值?

在 shell 脚本中,如何在完成一项工作后为变量赋予另一个值?

我正在尝试制作一个脚本,该脚本将查看该目录是否存在,并根据目录的名称/路径将其所有内容压缩到该目录下。

我能走的最远是——

#!/system/bin/sh -xv

Z="$PWD/../WorkingDir";
T='320';
F='480';
I='540';
D='dark';
L='light';
P='play';

cd $Z;

if [ -d $T/$D ]; then
    R=""$T"_"$D".zip";
else
    if [ -d $T/$L ]; then
        R=""$T"_"$L".zip";
    else
        R="file.zip";
    fi
fi;

for dir in */*/; do
    #Skip directories where the zip already exists
    [ -e "$dir"/"$R" ] || 
    ( cd -- "$dir" && zip -0rq "$R" .)
done

但这种情况发生了——

#!/system/bin/sh -xv
...
.
.
if [ -d $T/$D ]; then
    R=""$T"_"$D".zip";
else
    if [ -d $T/$L ]; then
        R=""$T"_"$L".zip";
    else
        R="file.zip";
    fi
fi;
+ [ -d 320/dark ]
+ R=320_dark.zip

for dir in */*/; do
    #Skip directories where the zip already exists
    [ -e "$dir"/"$R" ] ||
    ( cd -- "$dir" && zip -0rq "$R" .)
done
+ [ -e 320/dark//320_dark.zip ]
+ cd -- 320/dark/
+ zip -0rq 320_dark.zip .
+ [ -e 320/light//320_dark.zip ]
+ cd -- 320/light/
+ zip -0rq 320_dark.zip .
.
.
...and so on..

每个文件的名称都相同(320_dark.zip在这种情况下)。我希望每个压缩的文件都不同(根据文件夹名称/路径)。

我想了 -

+ [ -d 320/dark ]
+ R=320_dark.zip

- 每次更改每个文件夹。就像320_light.zip文件夹路径应该一样320/light

所以输出的最后一部分是 -

+ [ -e 320/dark//320_dark.zip ]
+ cd -- 320/dark/
+ zip -0rq 320_dark.zip .
+ [ -e 320/light//320_light.zip ]
+ cd -- 320/light/
+ zip -0rq 320_light.zip .

答案1

这是我的建议,为了保持一致性,删除单字母变量并更改存档的位置:

#!/system/bin/sh -xv

cd "$PWD/../WorkingDir"

compress() {
    # Detect only known dir names, convert slash to underscore
    local arch="$(echo $1 | sed -rne '/320\/(light|dark)/s@/@_@gp')"

    # Set a default value to the variable
    : ${arch:=file}

    # Only create a ZIP archive if not present in the parent directory
    # Note $PWD is evaluated *before* cd
    [ -f "${arch}.zip" ] || ( cd -- $1 && zip -0rq "${PWD}/${arch}.zip ." )
}

for dir in */*/; do
    compress $dir
done

只需更改该sed行以添加我所说的“众所周知的目录名称”即可。


编辑:根据OP的要求添加一些解释。

每次循环找到新目录时,脚本都会在压缩目录之前验证条件for。变量也被消除了。让我们剖析一下代码。

主循环

cd "$PWD/../WorkingDir"

for dir in */*/; do     # Ensures to select only directories
    compress $dir       # compress runs some checks prior to compressing
done

对此确实没什么可说的。

例行公事compress

local arch="$(echo $1 | sed -rne '/320\/(light|dark)/s@/@_@gp')"

$1是传递给 的参数compressed,即要检查和压缩的目录。sed首先 ( '/320\/(light|dark)/') 检查路径是否为以下形式

320/light
320/dark

并返回斜杠转换为下划线的路径:'s@/@_@g'。使用 at 符号作为分隔符以提高可读性,避免转义斜杠。其他有效的符号是's:/:_:g'or's#/#_#g'或 经典的's/\//_/g'。请注意如何使用反斜杠转义要转换的斜杠。我发现后一种形式的可读性较差。

尾随psed -n;一起使用。在这种特殊情况下,后一个选项意味着“p除非找到匹配项(即在包含的斜杠中),否则不要回显任何内容»。因此arch将包含一个斜杠转换为下划线的路径当且仅当320\/(light|dark)在路径中找到正则表达式。否则它不会回显任何内容,形成arch一个空白变量。

Option是告诉使用规范正则表达式的-r便捷方式,更具可读性。sed否则,您将需要转义括号和管道字符。我发现比or'/320\/(light|dark)/s@/@_@gp'更具可读性。'/320\/\(light\|dark\)/s@/@_@gp''/320\/\(light\|dark\)/s/\//_/gp'

: ${arch:=file}

如果该行为空,则设置arch为其默认值“file”。需要这种奇怪的构造,因为${arch:=file}单独构造会触发语法错误。冒号告诉 shell 不执行任何操作 ( ),但如果为空则:分配一个值。arch

    [ -f "${arch}.zip" ] || ( cd -- $1 && zip -0rq "${PWD}/${arch}.zip ." )

这里我使用了-fnot ,-e因为前者也会检查零长度文件。仅当 ZIP 存档存在时测试才会成功具有非零长度。

如果父级(或脚本的当前的) 目录,或者如果其大小为 null,则脚本会生成一个子 shell,该子 shell 会更改作为参数传递的目录compress并压缩其内容。请注意,变量$1$PWD被评估子 shell 执行其指令,即$PWD等于$Z初始版本中的父目录。

扩大过滤器

您可以按照sed以下方式进行操作:

sed -rne '/320\/(light|dark|play)/s@/@_@gp'

检查目录名称,例如

320/light
320/dark
320/play

您还可以考虑/(320|480|540)\/(light|dark|play)/,它为您提供 9 种组合,或更通用的形式/[0-9]+\/(light|dark|play)/(任何数字后跟斜杠和“之一”“,”黑暗的“ 和 ”") 或什至/[0-9]+\/\w+/(任何数字后跟一个斜杠和一个单词,又名[A-Za-z0-9_]+)。这完全取决于您希望过滤器的严格程度或广泛程度。

答案2

#!/system/bin/sh -xv

Z=/absolute/path/to/WorkingDir
T=320
F=480 # ?
I=540 # ?
D=dark
L=light
P=play # ?

cd $Z

for dir in $Z*/*/; do

    if [ -d $Z/$T/$D ] && [ ! -f $T$D.zip ]; then
        zip -0rq $T$D.zip $dir;            
    elif [ -d $Z/$T/$L ] && [ ! -f $T$L.zip ]; then      # elif rules
        zip -0rq $T$L.zip $dir;
    # It's not very efficient to scale this up, but you could add more elif statements here.
    elif [ -d $Z/$F/$D ] && [ ! -f $F$D.zip]; then
        zip -0rq $F$D.zip $dir;
    # and so on..
    else
        exit
    fi;
done

我想这就是你所需要的。如果需要任何调整,请告诉我。

相关内容