0

Intro

I have the output of the command xcrun simctl list devices on a file called simulators.txt:

-- iOS 13.1 --
    iPhone 11 (50E46560-28EE-4689-B015-01E86D9A2C8A) (Shutdown)
-- iOS 14.5 --
    iPhone 12 Pro (8F7AF263-396D-4256-803A-937FBC944795) (Booted) 
-- iOS 16.2 --
    iPhone 12 Pro (21CB340E-A08A-416A-BC28-78E26E42FC04) (Booted) 
    iPhone 14 Pro (62BA4ADD-7441-4D62-B137-C02A50867817) (Booted)
-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-16-0 --
    iPhone SE (3rd generation) (809AF9A3-5F67-4083-AF66-4F3B4C7B2138) (Shutdown) (unavailable, runtime profile not found)

My goal is to output this by filtering devices that are Booted:

* iPhone 12 Pro (iOS 14.5, 8F7AF263-396D-4256-803A-937FBC944795)
* iPhone 12 Pro (iOS 16.2, 21CB340E-A08A-416A-BC28-78E26E42FC04)
* iPhone 14 Pro (iOS 16.2, 62BA4ADD-7441-4D62-B137-C02A50867817)

Note that I need to preserve the model, version and UUId.


Things that I've tried so far

Using sed:

sed -ne 's/^-- iOS \(.*\) --/iOS \1:/p' -ne 's/^[ \t]*\(.*\) (Booted)/ * \1/p' < simulators.txt

I get:

iOS 13.1:
iOS 14.5:
  * iPhone 12 Pro (8F7AF263-396D-4256-803A-937FBC944795) 
iOS 16.2:
  * iPhone 12 Pro (21CB340E-A08A-416A-BC28-78E26E42FC04) 
  * iPhone 14 Pro (62BA4ADD-7441-4D62-B137-C02A50867817)

I would need to save the capture group from the first match (^-- iOS \(.*\) --) to a variable and apply it on the second match, but I'm not sure how to do that.

Using bash function

function displaySimulators {
    while IFS="" read -r p; do
        if [[ "$p" =~ --\ iOS.*\ -- ]]; then
            IOS_VERSION=$(echo $p | sed -ne 's/^-- \(.*\) --/\1/p')
        else
            echo $p | sed -ne 's/^[ \t]*\(.*\) (\(.*\)) (Booted)/* \1 ('"$IOS_VERSION"', \2)/p'
        fi
    done < simulators.txt
}

Here you can see that I applied the idea of saving the first match to a variable and reusing it when necessary.

The output is:

* iPhone 12 Pro (iOS 14.5, 8F7AF263-396D-4256-803A-937FBC944795)
* iPhone 12 Pro (iOS 16.2, 21CB340E-A08A-416A-BC28-78E26E42FC04)
* iPhone 14 Pro (iOS 16.2, 62BA4ADD-7441-4D62-B137-C02A50867817)

Which is what I need, but then some questions come to mind.


Questions

  1. How can I make the bash solution better? Are there any good practices or another approach that is faster and cleaner than this?
  2. How to achieve the same result using just sed or awk?
EdYuTo
  • 6,374
  • 3
  • 11
  • 22
  • 1
    The main thing that's icky about the bash function is the use of `sed`. If you're going to use `=~`, go all the way and use `BASH_REMATCH` to extract match groups. – Charles Duffy May 05 '23 at 01:37
  • 2
    And `echo $p` is itself buggy; see [I just assigned a variable, but `echo $variable` shows something else](https://stackoverflow.com/questions/29378566/i-just-assigned-a-variable-but-echo-variable-shows-something-else). Always, _always_, **always** quote your parameter expansions: `echo "$p"` – Charles Duffy May 05 '23 at 01:39
  • 1
    (much less importantly -- as a portability thing not a correctness thing -- stay away from the legacy ksh `function funcname {` syntax; the modern POSIX-defined standards-compliant function syntax is `funcname() {`) – Charles Duffy May 05 '23 at 01:40
  • 1
    btw, also consider storing your regexes in variables and using `[[ $string =~ $regex ]]`; more forgiving and portable across bash releases that way. – Charles Duffy May 05 '23 at 01:41
  • 1
    With `awk`, search for lines containing the string `(Booted)` and then throw away the last field (i.e. print all fields but the last). – user1934428 May 05 '23 at 06:41
  • @CharlesDuffy thanks for your insightful overview, i will make some changes with your suggestions – EdYuTo May 05 '23 at 13:08
  • I won't address the opinions you asked for but here's how to do what you need using any awk: `awk 'gsub(/^-- | --$/,""){ver=$0} sub(/ \(Booted).*/,""){sub(/[^()]+)/,ver", &"); $1="* "$1; print}' file`. If the question gets reopened I'll move that to an answer. That assumes the version such as in `-- iOS 13.1 --` can't contain `&` - if it can then include that case in your sample input/output. – Ed Morton May 06 '23 at 13:48

2 Answers2

1

or just use awk and do it in one shot :

mawk '(NF *= /^--/ ? "_"(__ = $2) : /[(]Booted[)]/) && 
        $2 = $2 " " __'   FS='^[ -]+|[ -]+$|[)]? [(]|[)]? (--|[(][^(]+)$'

 iPhone 12 Pro iOS 14.5 8F7AF263-396D-4256-803A-937FBC944795 
 iPhone 12 Pro iOS 16.2 21CB340E-A08A-416A-BC28-78E26E42FC04 
 iPhone 14 Pro iOS 16.2 62BA4ADD-7441-4D62-B137-C02A50867817 

to handle the annoying case of the iPhone SE (3rd generation) (assuming it's flagged "Booted"), you have to expand the logic by a tiny bit

gawk '(NF *= /^--/ ? "_" (__ = $2) : /[(]Booted[)]/) && 
        $2 = $2 (4 < NF ? " (" $3 ") " : " ")__'  \
          \
      FS='^[ -]+|[ -]+$|[)]? [(]|[)]? (--|[(][^(]+)$'

 iPhone 12 Pro iOS 14.5 8F7AF263-396D-4256-803A-937FBC944795 
 iPhone 12 Pro iOS 16.2 21CB340E-A08A-416A-BC28-78E26E42FC04 
 iPhone 14 Pro iOS 16.2 62BA4ADD-7441-4D62-B137-C02A50867817 
 iPhone SE (3rd generation) Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-16-0 3rd generation 809AF9A3-5F67-4083-AF66-4F3B4C7B2138 

caveat : this solution has an extra leading edge space

RARE Kpop Manifesto
  • 2,453
  • 3
  • 11
1
  • Assumption:

    Under the Unavailable: has Shutdown below/under it.


If ed is available/acceptable.


The script.ed name it to your own hearts content.

g?Booted?;?iOS?,t.
g/Shutdown/d
g?Booted?;?iOS?;+j
v/Booted/d
,s/ (Booted)//
g/./s/-- //g\
s/ --//g\
s/[[:space:]]\{2,\}/ /g
,s/^\(iOS [[:digit:]]\{1,\}\.[[:digit:]]\{1,\}\)\(.*(\)\(.*\)/*\2\1, \3/
,p
Q

The simulators.txt and its content.

-- iOS 13.1 --
    iPhone 30 (33E46888-38EE-9689-7015-01E86D9A2321) (Booted)
    iPhone 11 (50E46560-28EE-4689-B015-01E86D9A2C8A) (Shutdown)
    iPhone 25 (65446563-38EE-9689-7015-01E86D9A2XYA) (Booted)
    iPhone 25 (2AC46563-38EE-9689-7015-01E86D9A2BDP) (Booted)
    iPhone 18 (10E46563-38EE-9689-7015-01E86D9A2C8Z) (Shutdown)
-- iOS 14.5 --
    iPhone 12 Pro (8F7AF263-396D-8256-803A-337FBC944795) (Booted)
    iPhone 16 Pro (9F7AF263-596D-7256-803A-537FBC944796) (Booted)
    iPhone 19 Pro (5F7AF263-996D-2256-803A-437FBC944797) (Booted)
-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-16-0 --
    iPhone SE (10th generation) (809AF9A3-5F67-4083-AF66-4F3B4C7B2138) (Shutdown) (unavailable, runtime profile not found)
    iPhone SE (11t generation) (809AF9A3-5F67-4083-AF66-4F3B4C7B2138) (Shutdown) (unavailable, runtime profile not found)
-- iOS 16.2 --
    iPhone 12 Pro (21CB340E-A08A-416A-BC28-78E26E42FC04) (Booted)
    iPhone 14 Pro (62BA4ADD-7441-4D62-B137-C02A50867817) (Booted)
    iPhone 15 Pro (72CDkABB-9552-2C79-B137-Z02A50867819) (Booted)
-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-16-0 --
    iPhone SE (3rd generation) (809AF9A3-5F67-4083-AF66-4F3B4C7B2138) (Shutdown) (unavailable, runtime profile not found)
    iPhone SE (3rd generation) (809AF9A3-5F67-4083-AF66-4F3B4C7B2138) (Shutdown) (unavailable, runtime profile not found)

Run:

ed -s simulators.txt < script.ed

Output

* iPhone 30 (iOS 13.1, 33E46888-38EE-9689-7015-01E86D9A2321)
* iPhone 25 (iOS 13.1, 65446563-38EE-9689-7015-01E86D9A2XYA)
* iPhone 25 (iOS 13.1, 2AC46563-38EE-9689-7015-01E86D9A2BDP)
* iPhone 12 Pro (iOS 14.5, 8F7AF263-396D-8256-803A-337FBC944795)
* iPhone 16 Pro (iOS 14.5, 9F7AF263-596D-7256-803A-537FBC944796)
* iPhone 19 Pro (iOS 14.5, 5F7AF263-996D-2256-803A-437FBC944797)
* iPhone 12 Pro (iOS 16.2, 21CB340E-A08A-416A-BC28-78E26E42FC04)
* iPhone 14 Pro (iOS 16.2, 62BA4ADD-7441-4D62-B137-C02A50867817)
* iPhone 15 Pro (iOS 16.2, 72CDkABB-9552-2C79-B137-Z02A50867819)

  • Change Q to w if in_place editing is needed.

  • Remove the ,p to silence the output.

  • See GNU ed

  • See POSIX ed

Jetchisel
  • 7,493
  • 2
  • 19
  • 18
  • I wasn't aware of the `ed` line editor, but rn i won't be able to use it. Thanks for the detailed example – EdYuTo May 05 '23 at 13:25