2026-05-15 09:20:43 -07:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< link rel = "icon" type = "image/x-icon" href = "/favicon.ico" >
< title > azure locations and file crawling | hello hello</ title >
< meta name = "description" content = "Lee Cattarin... on the internet!" >
< link rel = "alternate" href = "/feed.xml" type = "application/atom+xml" title = "hello hello" >
< meta property = "og:title" content = "azure locations and file crawling | hello hello" >
< meta property = "og:type" content = "website" >
< meta property = "og:description" content = "Lee Cattarin... on the internet!" >
< meta property = "og:site_name" content = "hello hello" >
< meta property = "og:image" content = "/img/azure-locations.jpg" >
< meta property = "og:image:alt" content = "A Linux terminal. There is a fun rainbow flag in ascii art at the top, and then the user has called a command asking Azure for a list of locations applicable to a specific resource type. The output is lengthy." >
< meta name = "generator" content = "Eleventy v3.1.2" >
2026-05-21 23:35:46 +00:00
< meta itemprop = "ai-content-declaration:version" content = "1.0.0" >
< meta itemprop = "ai-content-declaration:level" content = "none" >
2026-05-15 09:20:43 -07:00
< link rel = "preconnect" href = "https://fonts.googleapis.com" >
< link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin = "" >
< link href = "https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Mono:ital,wght@0,200..800;1,200..800&family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel = "stylesheet" >
< script src = "https://kit.fontawesome.com/884dded219.js" crossorigin = "anonymous" ></ script >
< style >. post-metadata {
display : flex ;
flex-flow : row wrap ;
justify-content : space-between ;
align-items : baseline ;
margin : 1.5 rem 0 .5 rem ;
}
. post-metadata p {
font-size : .9 rem ;
margin : 0 ;
}
. post-tags {
display : flex ;
flex-flow : row wrap ;
gap : .5 rem ;
list-style : none ;
margin : 0 ;
}
. post-tags li {
margin : 0 ;
}
. post-tags li a {
text-decoration : none ;
color : var ( -- color - teal );
padding : 0 .5 rem ;
border-radius : 1 rem ;
box-shadow : .15 rem .15 rem var ( -- color - shadow );
border : .08 rem solid var ( -- color - teal );
line-height : 2 ;
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .1 s ease-in , left .1 s ease-in ;
}
. post-tags li a : focus-visible {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
. post-tags li a : hover {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
}
@ media ( forced-colors : active ) {
. post-tags li a : focus-visible {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
@ media ( any-hover : hover ) {
. post-tags li a : hover {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
}
}
/* Click animation */
. post-tags li a : active {
top : .1 rem ;
left : .1 rem ;
box-shadow : .05 rem .05 rem var ( -- color - shadow );
}
/* Adapted from PrismJS 1.30.0 Tomorrow Night theme
https://prismjs.com/download
*/
code ,
pre ,
code [ class *= language- ],
pre [ class *= language- ] {
font-family : var ( -- font - family - code );
background-color : var ( -- color - bg - alt );
font-size : .9 em ;
text-shadow : 0 1 px var ( -- color - shadow );
-moz- tab-size : 4 ;
-o- tab-size : 4 ;
tab-size : 4 ;
-webkit- hyphens : none ;
-moz- hyphens : none ;
-ms- hyphens : none ;
hyphens : none ;
}
pre ,
pre [ class *= language- ] {
margin : 1 rem 0 ;
padding : 1 rem ;
line-height : 1.5 ;
white-space : pre-wrap ;
word-break : break-word ;
overflow-wrap : break-word ;
border-radius : .5 rem ;
overflow : auto ;
}
: not ( pre )> code ,
: not ( pre )> code [ class *= language- ] {
padding : .2 rem ;
border-radius : .25 rem ;
white-space : normal ;
}
/* Selected text */
code :: -moz-selection ,
code :: -moz-selection ,
pre :: -moz-selection ,
pre :: -moz-selection ,
code [ class *= language- ] :: -moz-selection ,
code [ class *= language- ] :: -moz-selection ,
pre [ class *= language- ] :: -moz-selection ,
pre [ class *= language- ] :: -moz-selection ,
code :: selection ,
code :: selection ,
pre :: selection ,
pre :: selection ,
code [ class *= language- ] :: selection ,
code [ class *= language- ] :: selection ,
pre [ class *= language- ] :: selection ,
pre [ class *= language- ] :: selection {
text-shadow : none ;
background-color : var ( -- color - bg );
}
/* Syntax highlighting */
. token . namespace {
opacity : .7 ;
}
. token . bold ,
. token . important {
font-weight : 700
}
. token . italic {
font-style : italic
}
. token . block-comment ,
. token . cdata ,
. token . comment ,
. token . doctype ,
. token . prolog ,
. token . punctuation {
color : var ( -- color - grey );
}
. token . attr-name ,
. token . deleted ,
. token . namespace ,
. token . tag {
color : var ( -- color - red );
}
. token . boolean ,
. token . function ,
. token . number {
color : var ( -- color - orange );
}
. token . class-name ,
. token . constant ,
. token . property ,
. token . symbol {
color : var ( -- color - yellow );
}
. token . attr-value ,
. token . char ,
. token . regex ,
. token . string ,
. token . variable ,
. token . inserted {
color : var ( -- color - green );
}
. token . entity ,
. token . operator ,
. token . url ,
. token . function-name {
color : var ( -- color - blue );
}
. token . atrule ,
. token . builtin ,
. token . important ,
. token . keyword ,
. token . selector {
color : var ( -- color - purple );
}
# postlist ,
# taglist {
list-style : none ;
}
# postlist , . post ,
# taglist , . tag {
margin : 0 ;
}
/* Odd-numbered posts & tag layout/coloration */
. post : nth-child ( odd ) . postlink ,
. tag : nth-child ( odd ) . taglink {
grid-template-areas :
'img h2'
'img info'
'img .' ;
grid-template-columns : 45 % auto ;;
--color-primary : var ( -- color - teal );
--color-accent : var ( -- color - pink );
}
/* Even-numbered posts & tags layout/coloration */
. post : nth-child ( even ) . postlink ,
. tag : nth-child ( even ) . taglink {
grid-template-areas :
'h2 img'
'info img'
'. img' ;
grid-template-columns : auto 45 % ;
--color-primary : var ( -- color - pink );
--color-accent : var ( -- color - teal );
}
/* Layout for all posts on mobile */
@ media ( max-width : 650px ) {
. post : nth-child ( n ) . postlink ,
. tag : nth-child ( n ) . taglink {
grid-template-areas :
'img'
'h2'
'info' ;
grid-template-columns : auto ;
}
}
/* Link */
. postlink ,
. taglink {
display : grid ;
border : .25 rem solid var ( -- color - primary );
border-radius : 1.25 rem ;
box-shadow : .35 rem .35 rem var ( -- color - shadow );
margin : 2 rem 0 ;
text-decoration : none ;
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .05 s ease-in , left .05 s ease-in ;
}
. postlink : focus-visible ,
. taglink : focus-visible {
background-color : var ( -- color - primary );
outline : none ;
}
@ media ( any-hover : hover ) {
. postlink : hover ,
. taglink : hover {
background-color : var ( -- color - primary );
}
}
/* Forced colors */
@ media ( forced-colors : active ) {
. postlink : focus-visible ,
. taglink : focus-visible {
outline-offset : .25 rem ;
outline : .25 rem solid ;
}
@ media ( any-hover : hover ) {
. postlink : hover ,
. taglink : hover {
outline-offset : .25 rem ;
outline : .25 rem solid ;
}
}
}
/* Click animation */
. postlink : active ,
. taglink : active {
box-shadow : none ;
top : .2 rem ;
left : .2 rem ;
box-shadow : .15 rem .15 rem var ( -- color - shadow );
}
/* Post & tag elements */
. post h2 , . post img ,
. post ul , . post li ,
. tag h2 , . tag p ,
. tag img {
margin : 0 ;
}
. post h2 ,
. tag h2 {
grid-area : h2 ;
padding : .25 rem .5 rem ;
text-transform : uppercase ;
font-size : 1.5 rem ;
color : var ( -- color - primary );
border-radius : 1 rem 1 rem 0 0 ;
border-bottom : .25 rem solid var ( -- color - accent );
}
. post : nth-child ( even ) h2 ,
. tag : nth-child ( even ) h2 {
text-align : right ;
}
. postlink : focus-visible h2 ,
. taglink : focus-visible h2 {
color : var ( -- color - bg );
border-color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
. postlink : hover h2 ,
. taglink : hover h2 {
color : var ( -- color - bg );
border-color : var ( -- color - bg );
}
}
/* Images */
. post img ,
. tag-imgs {
grid-area : img ;
}
. blur {
filter : blur ( .75 rem );
clip-path : inset ( 0 round 1 rem );
}
. tag-imgs {
display : grid ;
grid-template-columns : repeat ( 2 , 1 fr );
gap : .15 rem ;
}
. tag-imgs img {
aspect-ratio : 3 / 2 ;
object-fit : cover ;
}
. missing-image {
width : 100 % ;
aspect-ratio : 3 / 2 ;
background-color : var ( -- color - bg - alt );
border-radius : 1 rem ;
}
. taglink : focus-visible . missing-image {
opacity : .7 ;
}
@ media ( any-hover : hover ) {
. taglink : hover . missing-image {
opacity : .7 ;
}
}
/* Post tags */
. postlist-tags {
grid-area : info ;
list-style : none ;
display : flex ;
flex-flow : row wrap ;
gap : .5 rem ;
padding : .5 rem ;
}
. post : nth-child ( odd ) . postlist-tags {
justify-content : flex-end ;
}
. postlist-tags li ,
. tagcount {
background-color : var ( -- color - primary );
color : var ( -- color - bg );
padding : 0 .5 rem ;
border-radius : 1 rem ;
}
. postlink : focus-visible . postlist-tags li ,
. taglink : focus-visible . tagcount {
background-color : var ( -- color - bg );
color : var ( -- color - primary );
}
@ media ( any-hover : hover ) {
. postlink : hover . postlist-tags li ,
. taglink : hover . tagcount {
background-color : var ( -- color - bg );
color : var ( -- color - primary );
}
}
/* Tag count */
. tag p {
grid-area : info ;
padding : .5 rem ;
}
. tag : nth-child ( odd ) p {
text-align : right ;
}
img [ tabindex = "0" ] {
cursor : pointer ;
}
img [ tabindex = "0" ] : focus-visible {
outline : .15 rem solid var ( -- color - teal );
}
dialog {
margin : auto ;
flex-flow : column ;
background : transparent ;
border : none ;
position : absolute ;
}
dialog [ open ] {
display : flex ;
}
dialog :: backdrop {
background-color : rgba ( from var ( -- color - bg ) r g b / .8 );
backdrop-filter : blur ( 4 px );
}
body : has ( dialog [ open ]) {
overflow : hidden ;
}
. close-dialog {
background-color : rgba ( from var ( -- color - teal ) r g b / .35 );
font-size : 1.5 rem ;
padding : 0 .5 rem .15 rem ;
border-radius : 1 rem ;
color : var ( -- color - teal );
box-shadow : .15 rem .15 rem var ( -- color - shadow );
border : .08 rem solid var ( -- color - teal );
align-self : flex-end ;
justify-self : flex-start ;
margin : 0 .1 rem ;
/* Click animation handling */
position : relative ;
top : 1 rem ;
left : -.15 rem ;
transition : top .1 s ease-in , left .1 s ease-in ;
}
. close-dialog : focus-visible {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
. close-dialog : hover {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
}
@ media ( forced-colors : active ) {
. close-dialog : focus-visible {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
@ media ( any-hover : hover ) {
. close-dialog : hover {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
}
}
/* Click animation */
. close-dialog : active {
top : 1.1 rem ;
left : -.05 rem ;
box-shadow : .05 rem .05 rem var ( -- color - shadow );
}
. modal-img {
max-height : calc ( 90 vh - 2 rem );
object-fit : contain ;
width : auto ;
max-width : 90 % ;
margin : 0 auto ;
}
: root {
color-scheme : light dark ;
--font-family : 'Atkinson Hyperlegible Next' , sans-serif ;
--font-family-code : 'Atkinson Hyperlegible Mono' , monospace ;
--color-dark : #2e303e ;
--color-dark-alt : #3c3f52 ;
--color-light : #ebeeef ;
--color-light-alt : #dbe1e3 ;
--color-teal-dark : #18737b ;
--color-teal-light : #25b0bc ;
--color-pink-dark : #94195d ;
--color-pink-light : #ee9fcb ;
--color-shadow : rgba ( 2 , 10 , 40 , .25 );
/* Used for syntax highlighting */
--color-red-light : #f195aa ;
--color-orange-light : #fab795 ;
--color-yellow-light : #fbe6bc ;
--color-green-light : #29d398 ;
--color-blue-light : #26bbd9 ;
--color-purple-light : #ddaeea ;
--color-grey-light : #b9c3c6 ;
--color-red-dark : #991433 ;
--color-orange-dark : #883206 ;
--color-yellow-dark : #6a4906 ;
--color-green-dark : #125940 ;
--color-blue-dark : #125663 ;
--color-purple-dark : #722999 ;
--color-grey-dark : #4a4b64 ;
--color-text : light-dark ( var ( -- color - dark ), var ( -- color - light ));
--color-bg : light-dark ( var ( -- color - light ), var ( -- color - dark ));
--color-text-alt : light-dark ( var ( -- color - dark - alt ), var ( -- color - light - alt ));
--color-bg-alt : light-dark ( var ( -- color - light - alt ), var ( -- color - dark - alt ));
--color-teal : light-dark ( var ( -- color - teal - dark ), var ( -- color - teal - light ));
--color-pink : light-dark ( var ( -- color - pink - dark ), var ( -- color - pink - light ));
--color-red : light-dark ( var ( -- color - red - dark ), var ( -- color - red - light ));
--color-orange : light-dark ( var ( -- color - orange - dark ), var ( -- color - orange - light ));
--color-yellow : light-dark ( var ( -- color - yellow - dark ), var ( -- color - yellow - light ));
--color-green : light-dark ( var ( -- color - green - dark ), var ( -- color - green - light ));
--color-blue : light-dark ( var ( -- color - blue - dark ), var ( -- color - blue - light ));
--color-purple : light-dark ( var ( -- color - purple - dark ), var ( -- color - purple - light ));
--color-grey : light-dark ( var ( -- color - grey - dark ), var ( -- color - grey - light ));
}
/* Base */
* {
box-sizing : border-box ;
margin : 0 ;
padding : 0 ;
}
body {
font-family : var ( -- font - family );
color : var ( -- color - text );
background-color : var ( -- color - bg );
}
main {
width : 60 vw ;
max-width : 1000 px ;
margin : 0 auto ;
scroll-margin-top : 7 rem ;
}
@ media ( max-width : 1050px ) {
main {
width : 75 vw ;
}
}
@ media ( max-width : 650px ) {
main {
width : 92 vw ;
}
}
/* Headers */
h1 , h2 , h3 , h4 , h5 , h6 {
line-height : 1.25 ;
color : var ( -- color - teal );
}
h1 {
margin-top : 3 rem ;
font-size : 3.5 rem ;
text-align : center ;
}
h2 , h3 , h4 , h5 , h6 {
scroll-margin-top : 5 rem ;
}
h2 {
margin-top : 2 rem ;
font-size : 2.2 rem ;
}
h3 {
margin-top : 1.5 rem ;
font-size : 1.6 rem ;
}
@ media ( max-width : 650px ) {
h1 { font-size : 2.8 rem ; }
h2 { font-size : 1.8 rem ; }
h3 { font-size : 1.35 rem ; }
}
h4 , h5 , h6 {
margin-top : 1 rem ;
font-size : 1.2 rem ;
}
/* Images */
img {
display : block ;
max-width : 100 % ;
height : auto ;
border-radius : 1 rem ;
margin : 0 auto ;
}
/* Paragraphs */
p {
margin : 1.25 rem 0 ;
line-height : 1.4 ;
}
strong ,
b {
font-weight : 900 ;
}
/* Links */
a {
color : var ( -- color - text );
border-radius : .25 rem ;
text-decoration : underline ;
text-decoration-style : solid ;
text-decoration-thickness : .2 em ;
text-decoration-color : var ( -- color - teal );
transition : text - decoration-thickness .5 s ;
}
a : focus-visible {
text-decoration : none ;
outline : .15 rem solid var ( -- color - teal );
}
@ media ( any-hover : hover ) {
a : hover {
text-decoration-thickness : .4 em ;
}
}
a : active {
text-decoration-thickness : .4 em ;
}
/* Heading anchors */
a . ha ,
span . ha-placeholder {
color : var ( -- color - pink );
font-size : .8 em ;
vertical-align : .1 em ;
}
span . ha-placeholder {
opacity : .55 ;
}
/* Lists */
:: marker {
color : var ( -- color - pink );
}
ul , ol , dl , li {
margin-left : 1 rem ;
}
@ media ( max-width : 650px ) {
ul , ol , dl {
margin-left : 0 ;
}
}
li {
line-height : 1.2 5 ;
margin-top : .65 rem ;
margin-bottom : .65 rem ;
}
li ul , li ol {
margin : .5 rem 0 ;
}
dt {
font-weight : 900 ;
margin-top : .5 rem ;
}
dd {
margin-left : 2 rem ;
margin-bottom : .75 rem ;
}
/* Blockquotes */
blockquote {
margin : .5 rem 0 ;
padding : 0 1 rem ;
border-radius : .25 rem 1 rem 1 rem .25 rem ;
line-height : 1.25 ;
border-left : .5 rem solid var ( -- color - pink );
}
blockquote ,
blockquote p ,
blockquote ol ,
blockquote ul {
background-color : var ( -- color - bg - alt );
padding : .5 rem ;
}
blockquote p {
margin : 0 ;
}
/* Tables */
table {
width : 100 % ;
border-spacing : 0 ; /* border collapse doesn't play nice with radii */
border-radius : .3 rem ;
border : thin solid var ( -- color - pink );
}
th {
color : var ( -- color - bg );
background-color : var ( -- color - pink );
}
th code {
color : var ( -- color - text ); /* Yes, I actually do this somewhere */
}
th , td {
padding : .5 rem ;
text-align : left ;
}
tr : nth-child ( even ) { background-color : var ( -- color - bg - alt ); }
th : not ( : first-child ) { border-left : thin solid var ( -- color - bg ); }
th : first-child { border-top-left-radius : .25 rem ; }
th : last-child { border-top-right-radius : .25 rem ; }
td : not ( : first-child ) { border-left : thin solid var ( -- color - pink ); }
/* Times */
time {
color : var ( -- color - grey );
}
/* Horizontal rules */
hr {
border : .25 rem solid var ( -- color - pink );
margin : 2 rem 0 ;
}
/* Used on home, reference, gallery pages */
. centered {
text-align : center ;
}
/* Currently only used for resume, but it's generalizable */
. upper {
text-transform : uppercase ;
}
/* Header */
header {
position : sticky ;
top : 0 ;
background-color : var ( -- color - bg );
padding : .75 rem 0 ;
z-index : 10 ;
border-bottom : thick solid var ( -- color - teal );
box-shadow : 0 .25 rem .15 rem var ( -- color - shadow );
}
/* Header links, pagination links */
header a ,
. pagination a ,
. webring ul a {
border-radius : 1 rem ;
border : .125 rem solid var ( -- color - pink );
color : var ( -- color - pink );
text-decoration : none ;
padding : 0 .25 rem ;
box-shadow : .15 rem .15 rem var ( -- color - shadow );
font-size : 1.2 rem ;
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .05 s ease-in , left .05 s ease-in ;
}
header a ,
. pagination . older a ,
. webring . prev a ,
. webring . rand a {
padding-right : .35 rem ;
}
. pagination . newer a ,
. webring . next a ,
. webring . rand a {
padding-left : .35 rem ;
}
header a : focus-visible ,
. pagination a : focus-visible ,
. webring ul a : focus-visible {
color : var ( -- color - bg );
border-color : var ( -- color - pink );
background-color : var ( -- color - pink );
outline : none ;
}
@ media ( any-hover : hover ) {
header a : hover ,
. pagination a : hover ,
. webring ul a : hover {
color : var ( -- color - bg );
border-color : var ( -- color - pink );
background-color : var ( -- color - pink );
}
}
@ media ( forced-colors : active ) {
header a : focus-visible ,
. pagination a : focus-visible ,
. webring ul a : focus-visible {
outline-offset : .125 rem ;
outline : .125 rem solid ;
}
@ media ( any-hover : hover ) {
header a : hover ,
. pagination a : hover ,
. webring ul a : hover {
outline-offset : .125 rem ;
outline : .125 rem solid ;
}
}
}
/* Click animation */
header a : active ,
. pagination a : active ,
. webring ul a : active {
top : .1 rem ;
left : .1 rem ;
box-shadow : .05 rem .05 rem var ( -- color - shadow );
}
/* Current page */
header a [ aria-current = "page" ] {
border-color : var ( -- color - teal );
color : var ( -- color - teal );
}
header a [ aria-current = "page" ] : focus-visible {
color : var ( -- color - bg );
border-color : var ( -- color - teal );
background-color : var ( -- color - teal );
}
@ media ( any-hover : hover ) {
header a [ aria-current = "page" ] : hover {
color : var ( -- color - bg );
background-color : var ( -- color - teal );
border-color : var ( -- color - teal );
}
}
/* Header link icons, pagination icons */
header i ,
. pagination i ,
. webring ul i {
color : var ( -- color - teal );
}
header i ,
. pagination . older i ,
. webring . prev i ,
. webring . rand i : nth-child ( 1 ) {
padding-left : .25 rem ;
}
. pagination . newer i ,
. webring . next i ,
. webring . rand i : nth-child ( 2 ) {
padding-right : .25 rem ;
}
header a [ aria-current = "page" ] i {
color : var ( -- color - pink );
}
header a : focus-visible i ,
a [ aria-current = "page" ] a : focus-visible i ,
. pagination a : focus-visible i ,
. webring ul a : focus-visible i {
color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
header a : hover i ,
header a [ aria-current = "page" ] : hover i ,
. pagination a : hover i ,
. webring ul a : hover i {
color : var ( -- color - bg );
}
}
/* Skip link */
# skip {
left : -999 px ;
position : absolute ;
top : auto ;
width : 1 px ;
height : 1 px ;
overflow : hidden ;
z-index : -99 ;
}
# skip : focus-visible {
display : inline-block ;
left : auto ;
top : auto ;
width : auto ;
height : auto ;
overflow : auto ;
margin : 0 10 % ;
z-index : 999 ;
}
/* Nav */
header ul {
display : flex ;
list-style : none ;
gap : 1 rem ;
justify-content : center ;
}
header ul ,
header li {
margin : 0 ;
}
@ media ( max-width : 650px ) {
. menu-text {
display : none ; /* Icons only on small screens */
}
header a {
padding : .15 rem .5 rem ;
}
header i {
padding : 0 ;
}
}
/* Footer */
footer {
padding : 1 rem 0 ;
font-size : .9 rem ;
border-top : thick solid var ( -- color - pink );
margin-top : 2 rem ;
}
footer ul {
display : flex ;
list-style : none ;
gap : .5 rem ;
justify-content : center ;
margin : 0 ;
}
footer li {
margin : 0 ;
}
footer li : nth-child ( 2 ) :: before ,
footer li : nth-child ( 2 ) :: after {
content : " ● " / "" ;
color : var ( -- color - teal );
}
@ media ( max-width : 650px ) {
footer ul {
flex-flow : column ;
text-align : center ;
}
footer li : nth-child ( 2 ) :: before ,
footer li : nth-child ( 2 ) :: after {
content : none ;
}
}
footer a {
text-decoration-color : var ( -- color - pink );
}
footer a : focus-visible {
outline-color : var ( -- color - pink );
}
/* Pagination */
. pagination ,
. pagination li {
margin : 0 ;
}
. pagination {
display : grid ;
grid-template-columns : repeat ( 2 , 1 fr );
grid-template-areas : "older newer" ;
list-style : none ;
margin-top : 3 rem ;
}
@ media ( max-width : 650px ) {
. post-pagination {
grid-template-columns : 1 fr ;
grid-template-areas :
"older"
"newer" ;
gap : .75 rem ;
}
}
. pagination . older {
grid-area : older ;
}
. pagination . newer {
grid-area : newer ;
text-align : right ;
}
/* webring navigation */
. webring {
margin-bottom : 3 rem ;
}
. webring ul {
display : flex ;
flex-flow : row wrap ;
list-style : none ;
justify-content : space-around ;
gap : .35 rem ;
}
. webring ul ,
. webring li {
margin-left : 0 ;
}
@ media print {
/* Nav elements */
header ,
footer ,
nav {
display : none !important ;
}
/* Base */
body {
background-color : #fff ;
color : #000 ;
}
main {
width : 95 vw ;
}
h1 , h2 , h3 , h4 , h5 , h6 {
color : #000 ;
}
/* Links */
/* Hover is not really necessary, but it's annoying when testing otherwise */
a ,
a : hover {
text-decoration-style : dotted ;
text-decoration-thickness : .1 rem ;
text-decoration-color : #000 ;
}
a :: after {
content : " (" attr ( href ) ")" ;
}
/* Code */
code ,
pre ,
code [ class *= language- ],
pre [ class *= language- ] {
text-shadow : none ;
background-color : var ( -- color - light );
color : #000 !important ;
}
. token . namespace {
opacity : 1 ;
}
. token . block-comment ,
. token . cdata ,
. token . comment ,
. token . doctype ,
. token . prolog ,
. token . punctuation ,
. token . attr-name ,
. token . deleted ,
. token . namespace ,
. token . tag ,
. token . boolean ,
. token . function ,
. token . number ,
. token . class-name ,
. token . constant ,
. token . property ,
. token . symbol ,
. token . attr-value ,
. token . char ,
. token . regex ,
. token . string ,
. token . variable ,
. token . inserted ,
. token . entity ,
. token . operator ,
. token . url ,
. token . function-name ,
. token . atrule ,
. token . builtin ,
. token . important ,
. token . keyword ,
. token . selector {
color : #000 ;
}
}</ style >
< script type = "module" > // Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0 ;
class HeadingAnchors extends HTMLElement {
static register ( tagName = "heading-anchors" , registry = window . customElements ) {
if ( registry && ! registry . get ( tagName )) {
registry . define ( tagName , this );
}
}
static attributes = {
exclude : "data-ha-exclude" ,
prefix : "prefix" ,
content : "content" ,
}
static classes = {
anchor : "ha" ,
placeholder : "ha-placeholder" ,
srOnly : "ha-visualhide" ,
}
static defaultSelector = "h2,h3,h4,h5,h6" ;
static css = `
. ${ HeadingAnchors . classes . srOnly } {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
. ${ HeadingAnchors . classes . anchor } {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
. ${ HeadingAnchors . classes . placeholder } {
opacity: .3;
}
. ${ HeadingAnchors . classes . anchor } :is(:focus-within, :hover) {
opacity: 1;
}
. ${ HeadingAnchors . classes . anchor } ,
. ${ HeadingAnchors . classes . placeholder } {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
. ${ HeadingAnchors . classes . anchor } {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}` ;
get supports () {
return "replaceSync" in CSSStyleSheet . prototype ;
}
get supportsAnchorPosition () {
return CSS . supports ( "anchor-name: none" );
}
constructor () {
super ();
if ( ! this . supports ) {
return ;
}
let sheet = new CSSStyleSheet ();
sheet . replaceSync ( HeadingAnchors . css );
document . adoptedStyleSheets = [... document . adoptedStyleSheets , sheet ];
this . headingStyles = {};
this . instanceIndex = globalInstanceIndex ++ ;
}
connectedCallback () {
if ( ! this . supports ) {
return ;
}
this . headings . forEach (( heading , index ) => {
if ( ! heading . hasAttribute ( HeadingAnchors . attributes . exclude )) {
let anchor = this . getAnchorElement ( heading );
let placeholder = this . getPlaceholderElement ();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if ( this . supportsAnchorPosition ) {
let anchorName = `--ha_ ${ this . instanceIndex } _ ${ index } ` ;
placeholder . style . setProperty ( "anchor-name" , anchorName );
anchor . style . positionAnchor = anchorName ;
}
heading . appendChild ( placeholder );
heading . after ( anchor );
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder ( placeholder ) {
if ( ! placeholder ) {
return ;
}
let heading = placeholder . closest ( "h1,h2,h3,h4,h5,h6" );
if ( ! heading . nextElementSibling ) {
return ;
}
// TODO next element could be more defensive
this . positionAnchor ( heading . nextElementSibling );
}
// Polyfill-only
positionAnchor ( anchor ) {
if ( ! anchor || ! anchor . previousElementSibling ) {
return ;
}
// TODO previous element could be more defensive
let heading = anchor . previousElementSibling ;
this . setFontProp ( heading , anchor );
if ( this . supportsAnchorPosition ) {
// quit early
return ;
}
let placeholder = heading . querySelector ( `. ${ HeadingAnchors . classes . placeholder } ` );
if ( placeholder ) {
anchor . style . setProperty ( "--ha_offsetx" , ` ${ placeholder . offsetLeft } px` );
anchor . style . setProperty ( "--ha_offsety" , ` ${ placeholder . offsetTop } px` );
}
}
setFontProp ( heading , anchor ) {
let placeholder = heading . querySelector ( `. ${ HeadingAnchors . classes . placeholder } ` );
if ( placeholder ) {
let style = getComputedStyle ( placeholder );
let props = [ "font-weight" , "font-size" , "line-height" , "font-family" ];
let [ weight , size , lh , family ] = props . map ( name => style . getPropertyValue ( name ));
anchor . style . setProperty ( "font" , ` ${ weight } ${ size } / ${ lh } ${ family } ` );
let vars = style . getPropertyValue ( "font-variation-settings" );
if ( vars ) {
anchor . style . setProperty ( "font-variation-settings" , vars );
}
}
}
/* no longer used, using aria-labelledby instead - see getAnchorElement
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
*/
getContent () {
if ( this . hasAttribute ( HeadingAnchors . attributes . content )) {
return this . getAttribute ( HeadingAnchors . attributes . content );
}
return "#" ;
}
// Placeholder nests inside of heading
getPlaceholderElement () {
let ph = document . createElement ( "span" );
ph . setAttribute ( "aria-hidden" , true );
ph . classList . add ( HeadingAnchors . classes . placeholder );
let content = this . getContent ();
if ( content ) {
ph . innerHTML = content ; // CHANGED HERE
}
ph . addEventListener ( "mouseover" , ( e ) => {
let placeholder = e . target . closest ( `. ${ HeadingAnchors . classes . placeholder } ` );
if ( placeholder ) {
this . positionAnchorFromPlaceholder ( placeholder );
}
});
return ph ;
}
getAnchorElement ( heading ) {
let anchor = document . createElement ( "a" );
anchor . href = `# ${ heading . id } ` ;
anchor . classList . add ( HeadingAnchors . classes . anchor );
let content = this . getContent ();
anchor . innerHTML = `<span aria-labelledby= ${ heading . id } > ${ content } </span>` ; // CHANGED HERE
anchor . addEventListener ( "focus" , e => {
let anchor = e . target . closest ( `. ${ HeadingAnchors . classes . anchor } ` );
if ( anchor ) {
this . positionAnchor ( anchor );
}
});
anchor . addEventListener ( "mouseover" , ( e ) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e . target . closest ( `. ${ HeadingAnchors . classes . anchor } ` );
this . positionAnchor ( anchor );
});
return anchor ;
}
get headings () {
return this . querySelectorAll ( this . selector . split ( "," ). map ( entry => ` ${ entry . trim () } [id]` ));
}
get selector () {
return this . getAttribute ( "selector" ) || HeadingAnchors . defaultSelector ;
}
}
HeadingAnchors . register ();
export { HeadingAnchors }
/* don't even bother on mobile */
if ( window . innerWidth > 650 ) {
const dialog = document . querySelector ( "dialog" );
const closeButton = document . querySelector ( ".close-dialog" );
const hero = document . querySelector ( ".hero" );
hero . tabIndex = 0 ;
hero . addEventListener ( "click" , ( e ) => dialog . showModal ());
hero . addEventListener ( "keydown" , ( e ) => {
if ( e . key === "Enter" || e . key === " " ) {
e . preventDefault ();
dialog . showModal ();
}
});
closeButton . addEventListener ( "click" , ( e ) => dialog . close ());
closeButton . addEventListener ( "keydown" , ( e ) => {
if ( e . key === "Enter" || e . key === " " ) {
e . preventDefault ();
dialog . close ();
}
});
}</ script >
</ head >
< body >
< header >
< a href = "#main" id = "skip" title = "skip to main content" >
< i class = "fa-solid fa-forward" aria-hidden = "true" ></ i > skip
</ a >
< nav aria-label = "main navigation" >
< ul >
< li >
< a href = "/reference/" title = "read reference posts" >
< i class = "fa-regular fa-folder-open" aria-hidden = "true" ></ i >
< span class = "menu-text" > reference</ span >
</ a >
</ li >
< li >
< a href = "/gallery/" title = "view the gallery" >
< i class = "fa-regular fa-images" aria-hidden = "true" ></ i >
< span class = "menu-text" > gallery</ span >
</ a >
</ li >
< li >
< a href = "/" title = "home" >
< i class = "fa fa-solid fa-crow" aria-hidden = "true" ></ i >
< span class = "menu-text" > home</ span >
</ a >
</ li >
< li >
< a href = "/about/" title = "about Lee" >
< i class = "fa-regular fa-user" aria-hidden = "true" ></ i >
< span class = "menu-text" > about</ span >
</ a >
</ li >
< li >
< a href = "/contact/" title = "contact Lee" >
< i class = "fa-solid fa-envelope-open-text" aria-hidden = "true" ></ i >
< span class = "menu-text" > contact</ span >
</ a >
</ li >
</ ul >
</ nav >
</ header >
< main id = "main" >
< heading-anchors content = "<i class='fa-solid fa-anchor'></i>" >
< article >
< h1 id = "azure-locations-and-file-crawling" > azure locations and file crawling</ h1 >
< div class = "post-metadata" >
< p >
posted on
< time datetime = "2025-05-14" > May 14, 2025</ time >
by Lee Cattarin
</ p >
< ul class = "post-tags" >
< li >
< a href = "/tags/software/" > software</ a >
</ li >
< li >
< a href = "/tags/highlight/" > highlight</ a >
</ li >
</ ul >
</ div >
< dialog closedby = "any" aria-label = "image modal" tabindex = "-1" >
< button class = "close-dialog" autofocus = "" aria-label = "close the image modal" > × </ button >
< img class = "modal-img" src = "/img/azure-locations.jpg" alt = "A Linux terminal. There is a fun rainbow flag in ascii art at the top, and then the user has called a command asking Azure for a list of locations applicable to a specific resource type. The output is lengthy." loading = "lazy" decoding = "async" width = "1000" height = "827" >
</ dialog >
< img class = "hero" src = "/img/azure-locations.jpg" alt = "A Linux terminal. There is a fun rainbow flag in ascii art at the top, and then the user has called a command asking Azure for a list of locations applicable to a specific resource type. The output is lengthy." loading = "lazy" decoding = "async" width = "1000" height = "827" >
< h2 id = "context" > context</ h2 >
< p > Azure is Microsoft's cloud offering. Each possible resource that can be deployed in Azure has a location it's deployed in, such as " East US" or " Italy." While some resources can be deployed in all locations, other resources have location constraints.</ p >
< p > It's common, when deploying, to have a whole ecosystem of resources that will work together. However, this introduces a problem: which locations work for all resources in a deployment?</ p >
< p > Let's dig in. (Want just the outcome? Check the < a href = "#summary" > summary</ a > .)</ p >
< h3 id = "bicep" > bicep</ h3 >
< p >< a href = "https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview?tabs=bicep" > Bicep</ a > is a language for describing Azure resources. A Bicep file sets out a series of resources with preset or parameterized properties in order to deploy said resources.</ p >
< p > A minimal Bicep file that creates a resource group might look like this:</ p >
< pre class = "language-bicep" >< code class = "language-bicep" >< span class = "token keyword" > param</ span > resourceGroupName < span class = "token datatype class-name" > string</ span > < span class = "token operator" > =</ span > < span class = "token string" > 'myResourceGroup'</ span >
< span class = "token keyword" > param</ span > location < span class = "token datatype class-name" > string</ span > < span class = "token operator" > =</ span > "westus2"
< span class = "token keyword" > resource</ span > resourceGroup < span class = "token string" > 'Microsoft.Resources/resourceGroups@2022-09-01'</ span > < span class = "token operator" > =</ span > < span class = "token punctuation" > {</ span >
< span class = "token property" > name</ span >< span class = "token operator" > :</ span > resourceGroupName
< span class = "token property" > location</ span >< span class = "token operator" > :</ span > location
< span class = "token punctuation" > }</ span ></ code ></ pre >
< p > This is easy to start parsing - I can use < code > grep</ code > to find that < code > Microsoft.Resources/resourceGroups@2022-09-01</ code > string and go from there.</ p >
< h4 id = "nesting" > nesting</ h4 >
< p > However, minimal is uncommon. As stated above, deployments of multiple resources are much more common.</ p >
< p > When working with large deployments, certain resources may be needed more than once. You can repeat your earlier storage account declaration, or, instead, you can template out how to deploy a storage account with given parameters, then reuse that template. This is called a < code > module</ code > , and it's fundamental to organizing Bicep files.</ p >
< p > Let's say this is our file structure. Ignore the lack of parameter files or READMEs, this is just an example.</ p >
< pre class = "language-txt" >< code class = "language-txt" > .
|--infra
|--env
| |--dev
| | |--main.bicep
| |--prod
| |--main.bicep
|--modules
|--rg
| |--main.bicep
|--vm
| |--modules
| | |--network.bicep
| | |--virtual-machine.bicep
| |--main.bicep
|--kv
|--modules
| |--role-assignment.bicep
| |--key-vault.bicep
|--main.bicep</ code ></ pre >
< p > Bicep files use relative references for local modules, so < code > infra/env/dev/main.bicep</ code > references < code > ../../modules/vm/main.bicep</ code > , which references < code > ./modules/network.bicep</ code > . While the directory structure in this example < em > could</ em > be flattened, my point is: modules can nest, and each module refers relatively to the module(s) it relies on.</ p >
< h2 id = "finding-all-resources" > finding all resources</ h2 >
< p > Okay, let's backtrack. From a given Bicep file, we want:</ p >
< ol >
< li > All referenced resource types</ li >
< li > All referenced modules</ li >
</ ol >
< h3 id = "grep" >< code > grep</ code ></ h3 >
< p > Resources and modules both have patterns in how they are declared. Thankfully, they're pretty simple regexes. < code > grep</ code > will spit out lines in a file that match a given regex.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token comment" > # this gets us strings like</ span >
< span class = "token comment" > # resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = {</ span >
< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^resource "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span >
< span class = "token comment" > # this gets us strings like</ span >
< span class = "token comment" > # module vm '../../modules/vm/main.bicep' = {</ span >
< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^module "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span ></ code ></ pre >
< h3 id = "cut" >< code > cut</ code ></ h3 >
< p > From there, let's use < code > cut</ code > to strip off the parts we don't want.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token comment" > # this gets us strings like</ span >
< span class = "token comment" > # Microsoft.Resources/resourceGroups</ span >
< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^resource "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > - < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "@"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -
< span class = "token comment" > # this gets us strings like</ span >
< span class = "token comment" > # ../../modules/vm/main.bicep</ span >
< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^module "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -</ code ></ pre >
< p > These calls are a little opaque. < code > -d</ code > sets a < strong > delimiter</ strong > (what to split on). < code > -f</ code > picks a < strong > field</ strong > to return, numbered from 1.</ p >
< h3 id = "mapfile" >< code > mapfile</ code ></ h3 >
< p > We'll save these values to variables. < code > mapfile</ code > reads a file, putting each line into a new array element. < code > -t</ code > < strong > trims</ strong > newline characters. The < code > < </ code > s do some redirection, and yes, the space between them < em > matters</ em > .</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^resource "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > - < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "@"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -< span class = "token punctuation" > )</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > modules < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^module "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -< span class = "token punctuation" > )</ span ></ code ></ pre >
< h3 id = "dirname-and-more" >< code > dirname</ code > (& more)</ h3 >
< p > We can't just stop there. We need to search each module in turn. Using < code > dirname</ code > , we can get the directory of the file we're searching, then append the relative module path.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token function-name function" > get_resources</ span > < span class = "token punctuation" > (</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > {</ span >
< span class = "token comment" > # ... grep, cut, etc ...</ span >
< span class = "token assign-left variable" > directory</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token function" > dirname</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span >< span class = "token variable" > )</ span ></ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > module</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${modules< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >
< span class = "token keyword" > do</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > < span class = "token parameter variable" > -O</ span > < span class = "token string" > "< span class = "token variable" > ${< span class = "token operator" > #</ span > resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "< span class = "token variable" > $directory</ span > /< span class = "token variable" > $module</ span > "</ span >< span class = "token punctuation" > )</ span >
< span class = "token keyword" > done</ span >
< span class = "token punctuation" > }</ span ></ code ></ pre >
< p > A lot just happened there besides < code > dirname</ code > . < code > {modules[@]}</ code > is all the array elements (as opposed to just < code > $modules</ code > , which evaluates to the first element). < code > ${#modules[@]}</ code > , on the other hand - note the pound sign - is the number of elements in the array.</ p >
< p > Additionally, < code > mapfile</ code > usually writes from index 0 onwards. But with the < code > -O</ code > argument, we can specify an < strong > origin</ strong > . By setting the starting point to the length of the array, we append to the array rather than writing over existing data.</ p >
< p > Finally, we got some recursion going! < code > get_resources</ code > calls < code > get_resources</ code > for every module found.</ p >
< h3 id = "the-get-resources-function" > the < code > get_resources</ code > function</ h3 >
< p > So far, our code looks like this:</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token function-name function" > get_resources</ span > < span class = "token punctuation" > (</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > {</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^resource "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > - < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "@"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -< span class = "token punctuation" > )</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > modules < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^module "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -< span class = "token punctuation" > )</ span >
< span class = "token assign-left variable" > directory</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token function" > dirname</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span >< span class = "token variable" > )</ span ></ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > module</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${modules< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >
< span class = "token keyword" > do</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > < span class = "token parameter variable" > -O</ span > < span class = "token string" > "< span class = "token variable" > ${< span class = "token operator" > #</ span > resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "< span class = "token variable" > $directory</ span > /< span class = "token variable" > $module</ span > "</ span >< span class = "token punctuation" > )</ span >
< span class = "token keyword" > done</ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > resource</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span >< span class = "token punctuation" > ;</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >
< span class = "token punctuation" > }</ span ></ code ></ pre >
< p > That last one-liner just returns our results. Note that we don't just < code > echo " ${resources[@]}" </ code > - this results in a space-delimited string and it'll be helpful later to have a newline-delimited string.</ p >
< h2 id = "finding-locations" > finding locations</ h2 >
< p > Now we need to use these resource types to get available locations. First, actually call our function from above. We'll assume we're in a directory with a top-level < code > main.bicep</ code > file.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "main.bicep"</ span >< span class = "token punctuation" > )</ span ></ code ></ pre >
< h3 id = "sort" >< code > sort</ code ></ h3 >
< p > Does sorting matter? Not really, but < code > sort</ code > has a useful feature, < code > -u</ code > , which returns < strong > u</ strong > nique items (aka, it deduplicates). Looking up the same resource type twice slows us down.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "main.bicep"</ span > < span class = "token operator" > |</ span > < span class = "token function" > sort</ span > -u< span class = "token punctuation" > )</ span ></ code ></ pre >
< p >< code > sort</ code > is one reason it helps to have newlines as delimiters - it expects that.</ p >
< h3 id = "az" >< code > az</ code ></ h3 >
< p > We'll use < code > az</ code > to list < em > all</ em > the locations - just to give ourselves a starting point. You could also use the locations for the first resource type.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > locations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > az account list-locations < span class = "token parameter variable" > --query</ span > < span class = "token string" > "[].displayName"</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --out</ span > tsv< span class = "token punctuation" > )</ span ></ code ></ pre >
< p > We can then use an < code > az</ code > command to find available locations for a given resource type:</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > newLocations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > az provider show < span class = "token parameter variable" > --namespace</ span > < span class = "token string" > "< span class = "token variable" > $namespace</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --query</ span > < span class = "token string" > "resourceTypes[?resourceType=='< span class = "token variable" > $resourceType</ span > '].locations | [0]"</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --out</ span > tsv< span class = "token punctuation" > )</ span ></ code ></ pre >
< p >< code > --out tsv</ code > means we will get a list with no decoration whatsoever - it's vital for programmatic handling of < code > az</ code > command output.</ p >
< h3 id = "cut-again" >< code > cut</ code > (again)</ h3 >
< p > We'll need to get those < code > $namespace</ code > and < code > $resourceType</ code > variables. < code > cut</ code > comes back in handy:</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token comment" > # remember, $resource is something like Microsoft.Resources/resourceGroups</ span >
< span class = "token comment" > # this gets us strings like</ span >
< span class = "token comment" > # Microsoft.Resources</ span >
< span class = "token assign-left variable" > namespace</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span > < span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "/"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -< span class = "token variable" > )</ span ></ span >
< span class = "token comment" > # this gets us strings like</ span >
< span class = "token comment" > # resourceGroups</ span >
< span class = "token assign-left variable" > resourceType</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span > < span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "/"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -< span class = "token variable" > )</ span ></ span ></ code ></ pre >
< h3 id = "comm" >< code > comm</ code ></ h3 >
< p > Okay, we can get locations. How do we handle finding their intersection?</ p >
< p >< code > comm</ code > to the rescue. It finds < strong > common</ strong > lines between two < em > sorted</ em > files. Its default output is three columns - lines only in file 1, lines only in file 2, and lines common to both. We can suppress the first two columns with < code > -12</ code > .</ p >
< p >< code > comm</ code > expects files, so we'll reuse our redirection < code > < (someCommand)</ code > from earlier.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > locations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > comm</ span > < span class = "token parameter variable" > -12</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${locations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${newLocations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > )</ span ></ code ></ pre >
< p >< code > comm</ code > also likes newline-delimited input, so we're again looping through the array rather than echoing all values at once.</ p >
< h3 id = "catching-errors" > catching errors</ h3 >
< p > With functionality as it is, many deployments will come back with 0 locations available. Turns out some basic resource types, like role assignments, don't have locations. So let's filter those.</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token keyword" > if</ span > < span class = "token punctuation" > [</ span >< span class = "token punctuation" > [</ span > < span class = "token variable" > ${< span class = "token operator" > #</ span > newLocations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > < span class = "token parameter variable" > -eq</ span > < span class = "token number" > 0</ span > < span class = "token punctuation" > ]</ span >< span class = "token punctuation" > ]</ span >
< span class = "token keyword" > then</ span >
< span class = "token comment" > # handle</ span >
< span class = "token keyword" > fi</ span ></ code ></ pre >
< h3 id = "tee" >< code > tee</ code ></ h3 >
< p > We'll print the locations to the shell. We can even use < code > tee</ code > to print them to a file for good measure:</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${locations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span > < span class = "token operator" > |</ span > < span class = "token function" > tee</ span > locations.txt</ code ></ pre >
< h3 id = "the-location-code" > the location code</ h3 >
< p > Here's our code for this section:</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "main.bicep"</ span > < span class = "token operator" > |</ span > < span class = "token function" > sort</ span > -u< span class = "token punctuation" > )</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > locations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > az account list-locations < span class = "token parameter variable" > --query</ span > < span class = "token string" > "[].displayName"</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --out</ span > tsv< span class = "token punctuation" > )</ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > resource</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >
< span class = "token keyword" > do</ span >
< span class = "token assign-left variable" > namespace</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span > < span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "/"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -< span class = "token variable" > )</ span ></ span >
< span class = "token assign-left variable" > resourceType</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span > < span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "/"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -< span class = "token variable" > )</ span ></ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > newLocations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > az provider show < span class = "token parameter variable" > --namespace</ span > < span class = "token string" > "< span class = "token variable" > $namespace</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --query</ span > < span class = "token string" > "resourceTypes[?resourceType=='< span class = "token variable" > $resourceType</ span > '].locations | [0]"</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --out</ span > tsv< span class = "token punctuation" > )</ span >
< span class = "token keyword" > if</ span > < span class = "token punctuation" > [</ span >< span class = "token punctuation" > [</ span > < span class = "token variable" > ${< span class = "token operator" > #</ span > newLocations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > < span class = "token parameter variable" > -eq</ span > < span class = "token number" > 0</ span > < span class = "token punctuation" > ]</ span >< span class = "token punctuation" > ]</ span >
< span class = "token keyword" > then</ span >
< span class = "token builtin class-name" > continue</ span >
< span class = "token keyword" > fi</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > locations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > comm</ span > < span class = "token parameter variable" > -12</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${locations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${newLocations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > )</ span >
< span class = "token keyword" > done</ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${locations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span > < span class = "token operator" > |</ span > < span class = "token function" > tee</ span > locations.txt</ code ></ pre >
< hr >
< h2 id = "summary" > summary</ h2 >
< p > Here's our final script:</ p >
< pre class = "language-sh" >< code class = "language-sh" >< span class = "token comment" > # Recursively crawls bicep files to find all referenced resources</ span >
< span class = "token function-name function" > get_resources</ span > < span class = "token punctuation" > (</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > {</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^resource "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > - < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "@"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -< span class = "token punctuation" > )</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > modules < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > grep</ span > < span class = "token parameter variable" > -E</ span > < span class = "token string" > "^module "</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "'"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -< span class = "token punctuation" > )</ span >
< span class = "token assign-left variable" > directory</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token function" > dirname</ span > < span class = "token string" > "< span class = "token variable" > $file</ span > "</ span >< span class = "token variable" > )</ span ></ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > module</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${modules< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >
< span class = "token keyword" > do</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > < span class = "token parameter variable" > -O</ span > < span class = "token string" > "< span class = "token variable" > ${< span class = "token operator" > #</ span > resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "< span class = "token variable" > $directory</ span > /module"</ span >< span class = "token punctuation" > )</ span >
< span class = "token keyword" > done</ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > resource</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >
< span class = "token punctuation" > }</ span >
< span class = "token comment" > # Execution starts here</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > resources < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > get_resources < span class = "token string" > "main.bicep"</ span > < span class = "token operator" > |</ span > < span class = "token function" > sort</ span > -u< span class = "token punctuation" > )</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > locations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > az account list-locations < span class = "token parameter variable" > --query</ span > < span class = "token string" > "[].displayName"</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --out</ span > tsv< span class = "token punctuation" > )</ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > resource</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${resources< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >
< span class = "token keyword" > do</ span >
< span class = "token assign-left variable" > namespace</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span > < span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "/"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 1</ span > -< span class = "token variable" > )</ span ></ span >
< span class = "token assign-left variable" > resourceType</ span >< span class = "token operator" > =</ span >< span class = "token variable" >< span class = "token variable" > $(</ span >< span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $resource</ span > "</ span > < span class = "token operator" > |</ span > < span class = "token function" > cut</ span > < span class = "token parameter variable" > -d</ span > < span class = "token string" > "/"</ span > < span class = "token parameter variable" > -f</ span > < span class = "token number" > 2</ span > -< span class = "token variable" > )</ span ></ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > newLocations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span > az provider show < span class = "token parameter variable" > --namespace</ span > < span class = "token string" > "< span class = "token variable" > $namespace</ span > "</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --query</ span > < span class = "token string" > "resourceTypes[?resourceType=='< span class = "token variable" > $resourceType</ span > '].locations | [0]"</ span > < span class = "token punctuation" > \</ span >
< span class = "token parameter variable" > --out</ span > tsv< span class = "token punctuation" > )</ span >
< span class = "token keyword" > if</ span > < span class = "token punctuation" > [</ span >< span class = "token punctuation" > [</ span > < span class = "token variable" > ${< span class = "token operator" > #</ span > newLocations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > < span class = "token parameter variable" > -eq</ span > < span class = "token number" > 0</ span > < span class = "token punctuation" > ]</ span >< span class = "token punctuation" > ]</ span >
< span class = "token keyword" > then</ span >
< span class = "token builtin class-name" > continue</ span >
< span class = "token keyword" > fi</ span >
< span class = "token builtin class-name" > mapfile</ span > < span class = "token parameter variable" > -t</ span > locations < span class = "token operator" > < </ span > < span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token function" > comm</ span > < span class = "token parameter variable" > -12</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${locations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > \</ span >
< span class = "token operator" > < </ span >< span class = "token punctuation" > (</ span >< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${newLocations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span >< span class = "token punctuation" > )</ span > < span class = "token punctuation" > )</ span >
< span class = "token keyword" > done</ span >
< span class = "token keyword" > for</ span > < span class = "token for-or-select variable" > location</ span > < span class = "token keyword" > in</ span > < span class = "token string" > "< span class = "token variable" > ${locations< span class = "token punctuation" > [</ span > @< span class = "token punctuation" > ]</ span > }</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > do</ span > < span class = "token builtin class-name" > echo</ span > < span class = "token string" > "< span class = "token variable" > $location</ span > "</ span >< span class = "token punctuation" > ;</ span > < span class = "token keyword" > done</ span > < span class = "token operator" > |</ span > < span class = "token function" > tee</ span > locations.txt</ code ></ pre >
</ article >
< nav aria-label = "pagination" >
< ol class = "pagination post-pagination" >
< li class = "older" >
< a href = "/fix-your-hearts/" >
< i class = "fa-solid fa-hand-point-left" aria-hidden = "true" ></ i > fix your hearts
</ a >
</ li >
< li class = "newer" >
< a href = "/redirections/" >
redirections < i class = "fa-solid fa-hand-point-right" aria-hidden = "true" ></ i >
</ a >
</ li >
</ ol >
</ nav >
< hr >
< section class = "related-posts" >
< h2 data-ha-exclude = "" id = "related-posts" > related posts</ h2 >
< ol id = "postlist" >
< li class = "post" >
2026-08-01 15:50:30 +00:00
< a class = "postlink" href = "/greeting-loons/" >
< h2 data-ha-exclude = "" id = "greeting-loons" > greeting loons </ h2 >
2026-08-01 15:48:58 +00:00
< ul class = "postlist-tags" >
2026-08-01 15:50:30 +00:00
< li > card</ li >
2026-08-01 15:48:58 +00:00
< li > print</ li >
< li > highlight</ li >
</ ul >
2026-08-01 15:50:30 +00:00
< img src = "/img/greeting-loons.jpg" alt = "A pile of hand-printed A2 size greeting cards. A loon rearing up with outstretched wings spans the front and back of the cards." loading = "lazy" decoding = "async" width = "1000" height = "750" >
2026-08-01 15:48:58 +00:00
</ a >
</ li >
< li class = "post" >
2026-08-01 15:50:30 +00:00
< a class = "postlink" href = "/backend-accessibility/" >
< h2 data-ha-exclude = "" id = "backend-accessibility" > backend accessibility </ h2 >
2026-07-26 22:09:10 +00:00
< ul class = "postlist-tags" >
2026-07-29 21:57:06 +00:00
< li > software</ li >
2026-07-26 22:09:10 +00:00
</ ul >
2026-08-01 15:50:30 +00:00
< img src = "/img/camelCase-print.jpg" alt = "A carved stamp next to its print. The print reads '#camelCase' in a slightly formal-looking italic font." loading = "lazy" decoding = "async" width = "1000" height = "750" >
</ a >
</ li >
< li class = "post" >
< a class = "postlink" href = "/screen-reader-optimizations/" >
< h2 data-ha-exclude = "" id = "screen-reader-optimizations" > screen reader optimizations </ h2 >
< ul class = "postlist-tags" >
< li > software</ li >
</ ul >
< img src = "/img/crow.jpg" alt = "Image unrelated to post. A crow poses on driftwood against a whitish sky." loading = "lazy" decoding = "async" width = "1000" height = "666" >
2026-05-15 09:20:43 -07:00
</ a >
</ li >
</ ol >
</ section >
</ heading-anchors >
</ main >
< footer >
< ul >
< li >
< a href = "/colophon/" >
colophon
</ a >
</ li >
< li >
< a href = "/" title = "go home" aria-label = "go home | hello hello from Lee Cattarin, copyright 2022-2026" >
hello hello from Lee Cattarin, © 2022-2026</ a >
</ li >
< li >
< a href = "https://heckin.technology/inherentlee/leecat.art" title = "source code" aria-label = "source code" target = "_blank" rel = "external" >
src
</ a >
</ li >
</ ul >
</ footer >
2026-08-01 15:50:30 +00:00
<!-- This page `/azure-locations-and-file-crawling/` was built on 2026-08-01T15:50:11.902Z -->
2026-05-15 09:20:43 -07:00
</ body >
</ html >