使用 Azure CLI 管理块 Blob

Blob 存储支持块 blob、追加 blob 和页 blob。 块 blob 经过优化,可高效地上传大量数据。 块 Blob 非常适合存储图像、文档和其他不受随机读写操作影响的数据类型。 本文说明如何处理块 blob。

先决条件

若要访问 Azure 存储,需要一个 Azure 订阅。 如果还没有订阅,请在开始前创建一个试用版订阅

对 Azure 存储进行的所有访问都要通过存储帐户完成。 对于本快速入门,请使用 Azure 门户、Azure PowerShell 或 Azure CLI 创建存储帐户。 有关如何创建存储帐户的帮助,请参阅创建存储帐户

  • 如需在本地运行 CLI 参考命令,请安装 Azure CLI。 如果在 Windows 或 macOS 上运行,请考虑在 Docker 容器中运行 Azure CLI。 有关详细信息,请参阅如何在 Docker 容器中运行 Azure CLI

    • 如果使用的是本地安装,请使用 az login 命令登录到 Azure CLI。 若要完成身份验证过程,请遵循终端中显示的步骤。 有关其他登录选项,请参阅使用 Azure CLI 登录

    • 出现提示时,请在首次使用时安装 Azure CLI 扩展。 有关扩展详细信息,请参阅使用 Azure CLI 的扩展

    • 运行 az version 以查找安装的版本和依赖库。 若要升级到最新版本,请运行 az upgrade

  • 本文需要 Azure CLI 版本 2.0.46 或更高版本。

授予对 Blob 存储的访问权限

可以使用 Microsoft Entra 凭据或存储帐户访问密钥通过 Azure CLI 授予对 Blob 存储的访问权限。 建议使用 Microsoft Entra 凭据,在本文中,相关示例仅使用 Microsoft Entra ID。

与针对 Blob 存储的数据操作相对应的 Azure CLI 命令支持 --auth-mode 参数,该参数用于指定如何授权给定操作。 将 --auth-mode 参数设置为登录,以使用 Microsoft Entra 凭据进行授权。 仅 Blob 存储数据操作支持 --auth-mode 参数。 管理操作(例如创建资源组或存储帐户)会自动将 Microsoft Entra 凭据用于授权。 有关详细信息,请参阅选择如何使用 Azure 门户授予对 Blob 数据的访问权限

运行 login 命令,以打开浏览器并连接到 Azure 订阅。


az login

创建容器

所有 blob 数据都存储在容器中,因此你需要至少一个容器资源,然后才能上传数据。 如果需要,请使用下面的示例创建存储容器。 有关详细信息,请参阅使用 Azure CLI 管理 Blob 容器


#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"

# Create a container object
az storage container create \
    --name $containerName \
    --account-name $storageAccount
    --auth-mode login

使用文本中包括的示例时,需要将括号中的占位符值替换为自己的值。 若要详细了解如何使用 Azure CLI 登录 Azure,请参阅使用 Azure CLI 登录

上传 Blob

Azure CLI 提供对一个资源或多个资源执行操作的命令,具体取决于你的要求。

若要将文件上传到块 Blob,请将所需的参数值传递给 az storage blob upload 命令。 使用 --file 参数提供源路径和文件名,并使用 --container-name 参数提供目标容器的名称。 此外,还需要提供 --account-name 参数。 此命令将创建新 Blob 或覆盖原始 Blob(如果已存在)。

可以使用 az storage blob upload-batch 命令以递归方式将多个 Blob 上传到存储容器。 可以使用 Unix 文件名模式匹配来指定要使用 --pattern 参数上传的文件范围。 支持的模式为 *?[seq][!seq]。 若要了解详细信息,请参阅有关 Unix 文件名模式匹配的 Python 文档。

在下面的示例中,第一个操作使用 az storage blob upload 命令上传单个命名文件。 使用 --file--container-name 参数指定源文件和目标存储容器。

第二个操作演示如何使用 az storage blob upload-batch 命令上传多个文件。 --if-modified-since 参数可确保仅上传过去七天内修改的文件。 此参数提供的值必须以 UTC 格式提供。


#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"
lastModified=$(date +%Y:%m:%d -d "7 days ago")

path="C:\\temp\\"
filename="demo-file.txt"
imageFiles="*.png"
file="$path$filename"

#Upload a single named file
az storage blob upload \
    --file $file \
    --container-name $containerName \
    --account-name $storageAccount \
    --auth-mode login

#Upload multiple image files recursively
az storage blob upload-batch \
    --destination $containerName \
    --source $path \
    --pattern *.png \
    --account-name $storageAccount \
    --auth-mode login \
    --if-modified-since $lastModified

列出 Blob

默认情况下,az storage blob list 命令列出一个容器中存储的所有 Blob。 你可以使用各种方法来缩小搜索的范围。 针对一个存储帐户可能拥有的容器或 blob 的数量,没有任何限制。 为了避免可能检索数千个 blob,最好限制返回的数据量。

使用 --prefix 参数可选择单个已知文件或名称以定义的字符串开头的一系列文件。 可以将虚拟目录指定为 --prefix 参数的一部分。

默认情况下,列表操作中仅返回 Blob。 在某些情况下,可能需要传递 --include 参数的值以返回其他类型的对象,例如软删除的 Blob、快照和版本。 可以组合这些值以返回多种对象类型。

--num-results 参数可用于限制从容器返回的 Blob 的数量。 对所有 Azure 资源上施加了 5,000 的服务限制。 此限制可确保检索可管理的数据量,且不会影响性能。 如果返回的 blob 数超过 --num-results 值或服务限制,则返回延续令牌。 此令牌允许使用多个请求来检索任意数量的 Blob。 枚举 blob 资源上提供了详细信息。

下面的示例演示了几种用于提供 blob 列表的方法。 第一种方法列出指定容器中的所有 Blob。 第二种方法使用 --prefix 参数列出以指定前缀开头的容器中的所有 blob。第三种方法使用 --num-results 参数来限制返回的结果,并使用 --show-next-marker 参数将延续令牌包含在结果中。 当结果中存在延续令牌时,它将传递给对 az storage blob list 的后续调用以检索下一组结果。

有关详细信息,请参阅 az storage blob list 参考。

#!/bin/bash
storageAccount="<storage-account>"
containerName="<container-name>"
blobPrefix="<prefix-string>"
numResults=5

#Approach 1: List all blobs in a container by name.

az storage blob list \
    --account-name $storageAccount \
    --container $containerName \
    --query "[].name" \
    --auth-mode login \
    --output tsv

#Approach 2: Use the --prefix parameter to list blobs starting with specified prefix.

az storage blob list \
    --account-name $storageAccount \
    --container $containerName \
    --prefix $blobPrefix \
    --query "[].name" \
    --auth-mode login \
    --output tsv

#Approach 3: Use the continuation token to return the complete set of results.

get_blobs() {
    if [ -z "$nextMarker" ]; then
        az storage blob list --container-name $containerName --num-results $numResults --account-name $storageAccount --show-next-marker --only-show-errors --auth-mode login
    else
        az storage blob list --container-name $containerName --num-results $numResults --marker $nextMarker --account-name $storageAccount --show-next-marker --only-show-errors --auth-mode login
    fi
}
 
total=0
nextMarker=""
while true; do
    blobs=$(get_blobs $containerName $numResults $storageAccount $nextMarker) 
    nextMarker=""
    blobsLength=$(echo $blobs | jq length)
    
    if [ $blobsLength -le 0 ]; then
        break
    fi
    
    blobIndex=0
    while read blob; do
        if [ $blobIndex -eq $(($blobsLength-1)) ]; 
        then
            nextMarker="$(echo $blob | jq -r .nextMarker)"
        else
            blobName=$(echo $blob | jq .name)
            echo "blobname: $blobName"
        fi
        ((blobIndex++))
    done <<<$(echo $blobs | jq -c '.[]')
 
    total=$(($total+$blobsLength-1))
    echo "Processed $total blobs so far"
    # echo "nextMarker: $nextMarker"
    if [ "${nextMarker}" = "null" ]; then
        echo -e "\nAccountName: $storageAccount, ContainerName: $containerName "
        echo "Processed $total blobs in total."
        break
    fi
done

下载 blob

根据用例,使用 az storage blob downloadaz storage blob download-batch 命令下载 Blob。 若要下载单个 Blob,请直接调用 az storage blob download 命令并传递 --container-name--file--name 参数的值。 默认情况下,该 Blob 将下载到 shell 目录,但也可以指定备用位置。 如果指定的路径不存在,该操作将失败并显示错误。

若要以递归方式从存储容器下载多个 Blob,请使用 az storage blob download-batch 命令。 此命令支持使用 --pattern 参数进行 Unix 文件名模式匹配。 支持的模式为 *?[seq][!seq]。 若要了解详细信息,请参阅有关 Unix 文件名模式匹配的 Python 文档。

下面的示例代码提供了单一下载和多个下载方法的示例。 它还提供了一种简化方法来使用通配符搜索特定文件的所有容器。 由于某些环境可能具有数千个资源,因此推荐使用 --num-results 参数。

有关其他信息,请参阅 az storage blob downloadaz storage blob download batch 参考。

#!/bin/bash
#Set variables
storageAccount="<storage-account>"
containerName="demo-container"

destinationPath="C:\\temp\\downloads\\"
destinationFilename="downloadedBlob.txt"
file="$destinationPath$destinationFilename"
sourceBlobName="demo-file.txt"

#Download a single named blob

az storage blob download \
    --container $containerName \
    --file $file \
    --name $sourceBlobName \
    --account-name $storageAccount \
    --auth-mode login

#Download multiple blobs using a pattern value

az storage blob download-batch \
    --destination $destinationPath \
    --source $containerName \
    --pattern images/*.png \
    --account-name $storageAccount \
    --auth-mode login

#Use a loop to download matching blobs in a list of containers

containerList=$( \
    az storage container list \
        --query "[].name" \
        --num-results 5 \
        --account-name $storageAccount \
        --auth-mode login \
        --output tsv 
)
for row in $containerList
do
    tmpName=$(echo $row | sed -e 's/\r//g')
    echo $tmpName
   
    az storage blob download-batch \
        --destination $destinationPath \
        --source $tmpName \
        --pattern *louis*.* \
        --account-name $storageAccount \
        --auth-mode login
done

管理 blob 属性和元数据

Blob 公开系统属性和用户定义的元数据。 每个 Blob 存储资源都存在系统属性。 有些属性是只读的,而其他属性可以读取或设置。 事实上,有些系统属性与某些标准 HTTP 头对应。

用户定义的元数据包含一个或多个你为 Blob 存储资源指定的名称/值对。 可以使用元数据存储资源的其他值。 元数据值用于你自己的目的,不会影响资源的行为方式。

读取 blob 属性

若要读取 blob 属性或元数据,必须首先从服务检索 blob。 使用 az storage blob show 命令检索到的是 Blob 的属性和元数据,而不是其内容。 下面的示例检索 blob 并列出其属性。

有关详细信息,请参阅 az storage blob show 参考。

#!/bin/bash
#Set variables
storageAccount="<storage-account>"
containerName="demo-container"

az storage blob show \
    --container  demo-container \
    --name demo-file.txt \
    --account-name $storageAccount \
    --auth-mode login

读取和写入 blob 元数据

Blob 元数据是与 blob 关联的名称/值对的可选集。 如上面的示例所示,最初没有与 blob 关联的元数据,但可以在需要时添加。 若要读取,请使用 az storage blob metadata show 命令。 若要更新 Blob 元数据,将使用 az storage blob metadata update 并提供键值对数组。 有关详细信息,请参阅 az storage blob metadata 参考。

有关详细信息,请参阅 az storage blob metadata 参考。

下面的示例首先更新,随后提交 blob 的元数据,然后进行检索。

#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"
blobName="blue-moon.mp3"

metadata=("Written=1934" "Recorded=1958")
metadata+=("Lyricist=Lorenz Hart")
metadata+=("Composer=Richard Rogers")
metadata+=("Artist=Tony Bennett")

#Update metadata
az storage blob metadata update \
    --container-name $containerName \
    --name $blobName \
    --metadata "${metadata[@]}" \
    --account-name $storageAccount \
    --auth-mode login

#Retrieve updated blob metadata
az storage blob metadata show \
    --container-name $containerName \
    --name $blobName \
    --account-name $storageAccount \
    --auth-mode login

用于 blob 的复制操作

在不同情况下,可以复制不同类型的 Blob。 本文中的示例仅限于块 blob。 Azure CLI 提供对一个资源或多个资源执行操作的命令,具体取决于你的要求。

若要复制特定 Blob,请使用 az storage blob copy start 命令,并为源和目标容器以及 Blob 指定值。 还可以提供统一资源标识符 (URI)、共享或共享访问签名 (SAS) 作为源。

此外,可以指定复制 Blob 的条件。 可以为源 Blob 或目标 Blob 设置这些条件。 可以引用上次修改日期、标记数据或 ETag 值。 例如,可以选择将最近未修改的 Blob 复制到单独的容器。 有关详细信息,请参阅为 Blob 服务操作指定条件标头

可以使用 az storage blob copy start-batch 命令以递归方式在同一存储帐户中的存储容器之间复制多个 Blob。 此命令需要 --source-container--destination-container 参数的值,可以在源和目标之间复制所有文件。 与其他 CLI 批处理命令一样,此命令支持使用 --pattern 参数进行 Unix 文件名模式匹配。 支持的模式为 *?[seq][!seq]。 若要了解详细信息,请参阅有关 Unix 文件名模式匹配的 Python 文档。

注意

请考虑使用 AzCopy 来简化操作和提高性能,尤其是在存储帐户之间复制 Blob 时。 AzCopy 是一个命令行实用工具,可用于向/从存储帐户复制 Blob 或文件。 了解有关如何开始使用 AzCopy 的详细信息。

有关详细信息,请参阅 az storage blob copy 参考。

以下示例代码提供了单个和多个复制操作的示例。 由于某些环境可能具有数千个资源,因此推荐使用 --num-results 参数。 第一个示例将 secret-town-road.png Blob 从 photos 容器复制到 locations 容器。 这两个容器处于同一个存储帐户中。 结果会验证复制操作是否成功。

#!/bin/bash
storageAccount="<storage-account>"
sourceContainer="photos"
blobName="secret-town-road.jpg"
destContainer="locations"

az storage blob copy start \
    --destination-container $destContainer \
    --destination-blob $blobName \
    --source-container $sourceContainer \
    --source-blob $blobName \
    --account-name $storageAccount \
    --auth-mode login

快照 blob

任何与基本 Blob 关联的租约都不会影响快照。 无法获取快照上的租约。 详细了解 Blob 快照。 有关详细信息,请参阅 az storage blob snapshot 参考。

下面的示例代码从存储容器检索 blob 并创建其快照。

#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"
blobName="demo-file.txt"

az storage blob snapshot \
    --container-name $containerName \
    --name Blue-Moon.mp3 \
    --account-name $storageAccount \
    --auth-mode login

设置 blob 层

更改 blob 的层时,会将 blob 及其所有数据移动到目标层。 可以使用 az storage blob set-tier 命令将层更改为“”、“”或“存档”。

还可以根据要求利用“复制 Blob”操作将 Blob 从一个层复制到另一个层。 “复制 Blob”操作将在所需的层中创建新的 Blob,同时将源 Blob 保留在原始层中。

几乎会立即将层级从“”或“”更改为“存档”。 在 Blob 移动到“存档”层之后,它被视为处于脱机状态,无法读取或修改。 你需要将其解除冻结到联机层,然后才能读取或修改已存档的 blob 数据。 详细了解存档层中的 Blob 解除冻结

有关详细信息,请参阅 az storage blob set-tier 参考。

下面的示例代码为 archive 容器中的单个命名 Blob 将层级设置为“”。

#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"

az storage blob set-tier 
    --container-name $containerName \
    --name Blue-Moon.mp3 \
    --tier Hot \
    --account-name $storageAccount \
    --auth-mode login

使用 Blob 标记的操作

Blob 索引标记可简化数据管理和发现。 Blob 索引标记是用户定义的键值索引属性,可以应用于 Blob。 配置这些标记后,可以在单个容器或所有容器中对对象进行分类和查找。 Blob 资源可以通过更新其索引标记来动态分类,而无需更改容器组织。 此方法提供了一种灵活的方式来应对不断变化的数据需求。 可以同时使用元数据和索引标记。 有关索引标记详细信息,请查看通过 blob 索引标记管理和查找 Azure Blob 数据

提示

下面提供的代码示例使用模式匹配从具有已知结构的 XML 文件获取文本。 该示例用于演示使用基本 Bash 功能添加 Blob 标记的简化方法。 在使用生产工作负载的数据时,始终建议使用实际的数据分析工具。

以下示例说明了如何将 Blob 索引标记添加到一系列 Blob。 该示例从 XML 文件中读取数据并使用它在多个 Blob 上创建索引标签。 要使用示例代码,请在 C:\temp 目录中创建一个本地 blob-list.xml 文件。 下面提供了 XML 数据。

有关详细信息,请参阅 az storage blob set-tier 参考。

<Venue Name="House of Prime Rib" Type="Restaurant">
  <Files>
    <File path="transactions/12027121.csv" />
    <File path="campaigns/radio-campaign.docx" />
    <File path="photos/bannerphoto.png" />
    <File path="archive/completed/2020review.pdf" />
    <File path="logs/2020/01/01/logfile.txt" />
  </Files>
</Venue>

此示例代码会循环访问 XML 文件内的行。 它查找 Venue 元素,并为 Name 和 Type 值创建变量。 然后,它会循环访问剩余行,并为 File 节点引用的每个 Blob 创建标记。

#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"

while read line
do
  
#Set Tag values 
if echo "$line" | grep -q "<Venue";then
    name=`echo "$line" | cut -d'"' -f 2`
    type=`echo "$line" | cut -d'"' -f 4`
    tags=("name=$name")
    tags+=("type=$type")
fi

#Add tags to blobs
if echo "$line" | grep -q "<File ";then
    blobName=`echo "$line" | cut -d'"' -f 2`
    
    echo az storage blob tag set \
        --container-name $containerName \
        --name $blobName \
        --account-name $storageAccount \
        --auth-mode login \
        --tags "{$tags[@]}"
fi

done < /mnt/c/temp/bloblist.xml

删除 Blob

可以使用 az storage blob deleteaz storage blob delete-batch 命令删除单个 Blob 或一系列 Blob。 删除多个 Blob 时,可以使用条件操作、循环或其他自动化操作,如以下示例所示。

警告

运行以下示例可能会永久删除 Blob。 Azure 建议启用容器软删除,防止意外删除容器和 Blob。 有关详细信息,请参阅容器的软删除

以下示例代码提供了单个删除和批量删除操作的示例。 第一个示例会删除单个命名 Blob。 第二个示例演示如何使用 Bash 中的逻辑操作来删除多个 Blob。 第三个示例使用 delete-batch 命令删除格式为 bennett-x(bennett-2 除外)的所有 Blob。

有关详细信息,请参阅 az storage blob deleteaz storage blob delete-batch 参考。

#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"

blobName="demo-file.txt"
blobPrefix="sinatra-"

#Delete a single, named blob
az storage blob delete \
    --container-name $containerName \
    --name $blobName \
    --account-name $storageAccount \
    --auth-mode login

#Iterate a blob list, deleting blobs whose names end with even numbers

## Get list of containers
blobList=$(az storage blob list \
    --query "[].name" \
    --prefix $blobPrefix \
    --container-name $containerName \
    --account-name $storageAccount \
    --auth-mode login \
    --output tsv)

## Delete all blobs with the format *bennett-x* except *bennett-2.*
for row in $blobList
do
    #Get the blob's number
    tmpBlob=$(echo $row | sed -e 's/\r//g') 
    tmpName=$(echo ${row%.*} | sed -e 's/\r//g')

    if [ `expr ${tmpName: ${#blobPrefix}} % 2` == 0 ]
    then
        
        echo "Deleting $tmpBlob"
        az storage blob delete \
            --container-name $containerName \
            --name $tmpBlob \
            --account-name $storageAccount \
            --auth-mode login

  fi
done

#Delete multiple blobs using delete-batch
az storage blob delete-batch \
    --source $containerName \
    --pattern bennett-[!2].* \
    --account-name $storageAccount \
    --auth-mode login

在某些情况下,可以检索已删除的 blob。 如果已启用存储帐户的软删除数据保护选项,则传递 --include d 参数时将返回在帐户保留期内删除的 Blob。 若要详细了解软删除,请参阅 Blob 软删除一文。

使用以下示例检索在容器的关联保留期内删除的 Blob 列表。 第一个示例显示最近删除的所有 Blob 及其删除日期的列表。 第二个示例列出与特定前缀匹配的所有已删除的 Blob。

#!/bin/bash
storageAccount="<storage-account>"
containerName="demo-container"

blobPrefix="sinatra-"

#Retrieve a list of all deleted blobs
az storage blob list \
    --container-name $containerName \
    --include d \
    --output table \
    --account-name $storageAccount \
    --auth-mode login \
    --query "[?deleted].{name:name,deleted:properties.deletedTime}"

#Retrieve a list of all deleted blobs matching a specific prefix
az storage blob list \
    --container-name $containerName \
    --prefix $blobPrefix \
    --output table \
    --include d \
    --account-name $storageAccount \
    --auth-mode login \
    --query "[].{name:name,deleted:deleted}"

还原已删除的 Blob

列出 blob 部分中所述,可以对存储帐户配置软删除数据保护选项。 启用后,可以还原在关联保持期内删除的容器。 你还可以使用版本控制来为每一次恢复和还原保留 Blob 的早期版本。

如果 Blob 版本控制和 Blob 软删除均已启用,那么,修改、改写、删除或还原 Blob 会自动创建新版本。 用于还原已删除 Blob 的方法将取决于存储帐户上是否启用了版本控制。

以下代码示例还原所有已软删除的 Blob,如果启用了版本控制,则还原 Blob 的最新版本。 它先用 az storage account blob-service-properties show 命令来确定是否启用了版本控制。

如果启用了版本控制,az storage blob list 命令会检索所有以唯一方式命名的 Blob 版本的列表。 接下来,检索列表中的 Blob 版本并按日期将它们排序。 如果未找到具有 isCurrentVersion 属性值的版本,则使用 az storage blob copy start 命令来制作 Blob 最新版本的活动副本。

如果禁用了版本控制,则使用 az storage blob undelete 命令来还原容器中每个被软删除的 Blob。

在按照此示例操作之前,需要先在至少一个存储帐户上启用软删除。 若要详细了解软删除数据保护选项,请参阅 Blob 软删除一文或 az storage blob undelete 参考。

#!/bin/bash
storageAccount="<storage-account>"
groupName="myResourceGroup"
containerName="demo-container"

blobSvcProps=$(
    az storage account blob-service-properties show \
        --account-name $storageAccount \
        --resource-group $groupName)

softDelete=$(echo "${blobSvcProps}" | jq -r '.deleteRetentionPolicy.enabled')
versioning=$(echo "${blobSvcProps}" | jq -r '.isVersioningEnabled')

# If soft delete is enabled
if $softDelete
then
    
    # If versioning is enabled
    if $versioning
    then

        # Get all blobs and versions using -Unique to avoid processing duplicates/versions
        blobList=$(
            az storage blob list \
                --account-name $storageAccount \
                --container-name $containerName \
                --include dv \--query "[?versionId != null].{name:name}" \
                --auth-mode login -o tsv | uniq)
        
        # Iterate the collection
        for blob in $blobList
        do
            # Get all versions of the blob, newest to oldest
            blobVers=$(
                az storage blob list \
                    --account-name $storageAccount \
                    --container-name $containerName \
                    --include dv \
                    --prefix $blob \
                    --auth-mode login -o json | jq 'sort_by(.versionId) | reverse | .[]')
            # Select the first (newest) object
            delBlob=$(echo "$blobVers" | jq -sr '.[0]')
            
            # Verify that the newest version is NOT the latest (that the version is "deleted")
            if [[ $(echo "$delBlob" | jq '.isCurrentVersion') != true ]]; 
            then
                # Get the blob's versionId property, build the URI to the blob
                versionID=$(echo "$delBlob" | jq -r '.versionId')
                uri="https://$storageAccount.blob.core.chinacloudapi.cn/$containerName/$blob?versionId=$versionID"
                
                # Copy the latest version 
                az storage blob copy start \
                    --account-name $storageAccount \
                    --destination-blob $blob \
                    --destination-container $containerName \
                    --source-uri $uri \
                    --auth-mode login
       
                delBlob=""
            fi
        done

    else

        #Retrieve all deleted blobs
        blobList=$( \
            az storage blob list \
                --container-name $containerName \
                --include d \
                --output tsv \
                --account-name $storageAccount \
                --auth-mode login \
                --query "[?deleted].[name]" \
        )

        #Iterate list of deleted blobs and restore
        for row in $blobList
        do
            tmpName=$(echo $row | sed -e 's/\r//g')
            echo "Restoring $tmpName"
            az storage blob undelete \
                --container-name $containerName \
                --name $tmpName \
                --account-name $storageAccount \
                --auth-mode login
        done

    fi

else
    
    #Soft delete is not enabled
    echo "Sorry, the delete retention policy is not enabled."

fi

后续步骤