shell 用于压缩包含记录数和特定命名约定的文件的脚本
shell script to zip the files with number of records and with particular naming convention
我们想将文件压缩到目录中,记录数和目录命名约定遵循 zip 文件。
例如:我们有两个带有日期名称的目录(2021-10-01、2021-10-02,每个父目录都包含带有国家名称的子目录,并且这个国家目录包含文件数。
2021-10-01/USA, 2021-10-01/UK
2021-10-02/USA, 2021-10-02/USA
我们想压缩记录数量有限的国家/地区目录,zip 文件应命名为 parentdirectory_Countrydirectory.zip(2021-10-01_USA.zip)
。
我的脚本接受日期作为参数,并将其传递给 sql 查询,该查询将提取具有日期父目录结构的数据,其中包含来自数据库的文件的数据中的国家/地区子目录,但我只是在此处跳过脚本的 sql 查询部分。
#!/bin/bash
startd=
endd=
compress () {
startd=$(date -d $startd +%Y%m%d)
endd=$(date -d $endd +%Y%m%d)
while [[ $startd -le $endd ]]
do
tempdate=$(date -d $startd +"%Y-%m-%d")
dirl+=" $tempdate"
startd=$(date -d"$startd + 1 day" +"%Y%m%d")
done
echo $dirl
for j in $dirl
do
if [ -d "$j" ]; then
cd $j
for d in *
do
zip ${j}_${d}.zip $d
mv ${j}_${d}.zip ../
done
else
echo "no data extracted on: $j"
fi
cd ..
done
}
我想压缩记录数量限制的文件,名称可以是 parentdirectory_subdirectory1.zip 具有相同命名约定的增量。
注意:记录数是指通过 sql 查询提取的子目录中的文件,USA 子目录可能包含数千个文件,所以我想将 zip 与子目录文件分开,例如 200 files 然后使用相同的命名约定创建文件,例如 2021-10-01_USA.zip 2021-10-01_USA1.zip 等
在 Bash 中这有点棘手,但您可以使用例如xargs
方便地将一长串项目拆分为可管理的块。接下来的挑战是为每个 zip 文件传递一个新的文件名。这是一种快速而肮脏的尝试。
compress () {
local startd=$(date -d "" +%Y%m%d)
local endd=$(date -d "" +%Y%m%d)
local mm
local j
local d
while [[ $startd -le $endd ]]
do
mm=${startd#??}
j="${startd%????}-${mm%??}-${mm#??}")
startd=$(date -d"$startd + 1 day" +"%Y%m%d")
if [ -d "$j" ]; then
for d in "$j"/*/; do
printf '%s[=10=]' "$j"/"$d"/* |
xargs -r -0 -n 200 sh -c '
for ((i=0; i<=99; i++)); do
test -e "[=10=]${i#0}.zip" || break
done
zip -j "[=10=]${i#0}.zip" "$@"' ../"${j}_${d}"
done
else
echo "[=10=]: no data extracted on: $j" >&2
fi
done
}
随机观察:
- 请尽量使用标准缩进;空格的随机变化会让读者和你自己感到困惑。
- 调用函数时应将参数传递给函数,而不是存储在全局变量中。
- 随机引用修复;另见 When should I wrap quotes around a shell variable?
对我们要循环的日期使用数组其实只是一个一个处理日期然后忘记它们,而不是先单独收集到内存中。
- 与其再次调用
date
以在数组中以 yyyy-mm-dd 格式插入破折号,不如使用一系列参数扩展。这在代码方面有点乏味,但避免了调用外部进程来处理 shell 可以使用内部设施 更快地完成的事情
- 直接在父目录中创建 zip 文件,而不是在完成后移动它们
- 我们使用
zip -j
从输入文件中删除目录名称,这样我们就不必 cd
进出每个目录。 (如果你有目录符号链接,这有点容易出错。)
- 将错误消息发送到标准错误
>&2
并在消息本身中包含创建消息的脚本的名称。
真正的内容在稍微复杂的 xargs
调用中。
我们printf
将要压缩的文件名作为空分隔项,以便我们可以正确处理任意文件名。 (参见 http://mywiki.wooledge.org/BashFAQ/020 for details.) The -0
argument to xargs
is a GNU extension to enable this. The -r
argument simply says to do nothing if there is no input (i.e. there were no files in the directory; probably shopt -s nullglob
too)。
-n 200
说限制一次最多输入 200 个文件,然后我们将这 200 个或更少的文件名传递给 sh -c
脚本。
... 它接收我们要创建的 zip 文件的基本名称 [=24=]
(这只是一个 hack,以避免必须从参数列表中单独 shift
关闭参数它接收;sh -c
的第一个参数通常不被使用,所以我们用它来走私这个值)。它使用一个简单的 for
循环来查找具有此前缀的第一个未使用的名称,第一个使用空字符串。
(也许改变这个 - 我认为你提出的约定有点混乱。我宁愿只有 xxx.zip
只有一个文件在集合中,并且 xxx1.zip
, xxx2.zip
, 等有几个时。)
一旦我们确定了文件名,我们只需zip
我们收到的文件作为该文件的参数。
xargs
负责将输入文件集分成所需大小的块,并根据需要多次调用 sh -c
脚本。
起初这可能有点吓人;这在像 Python.
这样的现代脚本语言中会更容易一些
我们想将文件压缩到目录中,记录数和目录命名约定遵循 zip 文件。
例如:我们有两个带有日期名称的目录(2021-10-01、2021-10-02,每个父目录都包含带有国家名称的子目录,并且这个国家目录包含文件数。
2021-10-01/USA, 2021-10-01/UK
2021-10-02/USA, 2021-10-02/USA
我们想压缩记录数量有限的国家/地区目录,zip 文件应命名为 parentdirectory_Countrydirectory.zip(2021-10-01_USA.zip)
。
我的脚本接受日期作为参数,并将其传递给 sql 查询,该查询将提取具有日期父目录结构的数据,其中包含来自数据库的文件的数据中的国家/地区子目录,但我只是在此处跳过脚本的 sql 查询部分。
#!/bin/bash
startd=
endd=
compress () {
startd=$(date -d $startd +%Y%m%d)
endd=$(date -d $endd +%Y%m%d)
while [[ $startd -le $endd ]]
do
tempdate=$(date -d $startd +"%Y-%m-%d")
dirl+=" $tempdate"
startd=$(date -d"$startd + 1 day" +"%Y%m%d")
done
echo $dirl
for j in $dirl
do
if [ -d "$j" ]; then
cd $j
for d in *
do
zip ${j}_${d}.zip $d
mv ${j}_${d}.zip ../
done
else
echo "no data extracted on: $j"
fi
cd ..
done
}
我想压缩记录数量限制的文件,名称可以是 parentdirectory_subdirectory1.zip 具有相同命名约定的增量。
注意:记录数是指通过 sql 查询提取的子目录中的文件,USA 子目录可能包含数千个文件,所以我想将 zip 与子目录文件分开,例如 200 files 然后使用相同的命名约定创建文件,例如 2021-10-01_USA.zip 2021-10-01_USA1.zip 等
在 Bash 中这有点棘手,但您可以使用例如xargs
方便地将一长串项目拆分为可管理的块。接下来的挑战是为每个 zip 文件传递一个新的文件名。这是一种快速而肮脏的尝试。
compress () {
local startd=$(date -d "" +%Y%m%d)
local endd=$(date -d "" +%Y%m%d)
local mm
local j
local d
while [[ $startd -le $endd ]]
do
mm=${startd#??}
j="${startd%????}-${mm%??}-${mm#??}")
startd=$(date -d"$startd + 1 day" +"%Y%m%d")
if [ -d "$j" ]; then
for d in "$j"/*/; do
printf '%s[=10=]' "$j"/"$d"/* |
xargs -r -0 -n 200 sh -c '
for ((i=0; i<=99; i++)); do
test -e "[=10=]${i#0}.zip" || break
done
zip -j "[=10=]${i#0}.zip" "$@"' ../"${j}_${d}"
done
else
echo "[=10=]: no data extracted on: $j" >&2
fi
done
}
随机观察:
- 请尽量使用标准缩进;空格的随机变化会让读者和你自己感到困惑。
- 调用函数时应将参数传递给函数,而不是存储在全局变量中。
- 随机引用修复;另见 When should I wrap quotes around a shell variable?
对我们要循环的日期使用数组其实只是一个一个处理日期然后忘记它们,而不是先单独收集到内存中。- 与其再次调用
date
以在数组中以 yyyy-mm-dd 格式插入破折号,不如使用一系列参数扩展。这在代码方面有点乏味,但避免了调用外部进程来处理 shell 可以使用内部设施 更快地完成的事情
- 直接在父目录中创建 zip 文件,而不是在完成后移动它们
- 我们使用
zip -j
从输入文件中删除目录名称,这样我们就不必cd
进出每个目录。 (如果你有目录符号链接,这有点容易出错。) - 将错误消息发送到标准错误
>&2
并在消息本身中包含创建消息的脚本的名称。
真正的内容在稍微复杂的 xargs
调用中。
我们printf
将要压缩的文件名作为空分隔项,以便我们可以正确处理任意文件名。 (参见 http://mywiki.wooledge.org/BashFAQ/020 for details.) The -0
argument to xargs
is a GNU extension to enable this. The -r
argument simply says to do nothing if there is no input (i.e. there were no files in the directory; probably shopt -s nullglob
too)。
-n 200
说限制一次最多输入 200 个文件,然后我们将这 200 个或更少的文件名传递给 sh -c
脚本。
... 它接收我们要创建的 zip 文件的基本名称 [=24=]
(这只是一个 hack,以避免必须从参数列表中单独 shift
关闭参数它接收;sh -c
的第一个参数通常不被使用,所以我们用它来走私这个值)。它使用一个简单的 for
循环来查找具有此前缀的第一个未使用的名称,第一个使用空字符串。
(也许改变这个 - 我认为你提出的约定有点混乱。我宁愿只有 xxx.zip
只有一个文件在集合中,并且 xxx1.zip
, xxx2.zip
, 等有几个时。)
一旦我们确定了文件名,我们只需zip
我们收到的文件作为该文件的参数。
xargs
负责将输入文件集分成所需大小的块,并根据需要多次调用 sh -c
脚本。
起初这可能有点吓人;这在像 Python.
这样的现代脚本语言中会更容易一些