# Extracting parts of a string

**URL:** <https://forum.ansible.com/t/extracting-parts-of-a-string/4941>\
**Category:** Get Help\
**Created:** [April 14, 2024, 12:23pm UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941 "2024-04-14T12:23:56Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![dulhaver](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/dulhaver/32/1061_2.png) [@dulhaver](https://forum.ansible.com/u/dulhaver)\
**Post date:** [April 14, 2024, 12:23pm UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/1 "2024-04-14T12:23:56Z")

</div>

this is kind of a follow up quesiton on [Unarchive - using wildcards in 'src' option](http://forum.ansible.com/t/unarchive-using-wildcards-in-src-option/4876)

So, I am getting a value like `/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz` baked into a variable which I can address via `nexus_tar.path`.

This results into an unarchived directory later down the line named `/opt/nexus/nexus-3.67.1-01`.

Now I want to create a symlink to that directory, but only have `/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz` to work with.

how do I extract `nexus-3.67.1-01` from `/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz` in order to use that in a new path? I think it is python string manipulation knowledge (which apparently I am lacking) being needed here.

I can figure out something like this

```auto
❯ python

>>> path = '/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz'
>>> short_path = path.replace("/opt/nexus/install/","")
>>> version = short_path.replace("-unix.tar.gz" , "")
>>> version
'nexus-3.67.1-01'

```

or

```auto
>>> import re
>>> file_path = "/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz"
>>> re.search(r'(nexus-.*?)-unix.tar.gz', file_path).group(1)
'nexus-3.67.1-01'

```

which, besides from probably being horrible python, makes me confident that it is something along those lines.

Can anybody kindly explain how to translate something along those python lines in anything like i.E.

```yaml
- name: extract nexus-version
  set_fact:
     nexus_path: "/opt/nexus/{{ nexus_tar.path ..... }}"

```

or is there another approach to it?

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [April 14, 2024, 1:30pm UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/2 "2024-04-14T13:30:34Z")

</div>

> [@dulhaver](#):
>
> how do I extract `nexus-3.67.1-01` from `/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz` in order to use that in a new path?

I posted an answer for that in [the last thread](http://forum.ansible.com/t/unarchive-using-wildcards-in-src-option/4876/4), you can use the basename filter to get just the filename and [regex\_replace filter](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/regex_replace_filter.html) to remove the start and the ends of the filename, for example, something like this:

```yaml
- name: Set a fact for the Nexus version
  ansible.builtin.set_fact:
    nexus_version: >-
      {{ nexus_path |
      ansible.builtin.basename |
      ansible.builtin.regex_replace('^nexus-') |
      ansible.builtin.regex_replace('-unix[.]tar[.]gz$') }}
  vars:
    nexus_path: /opt/nexus/install/nexus-3.67.1-01-unix.tar.gz

```

---

<div class="post-metadata">

**Author:** ![dulhaver](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/dulhaver/32/1061_2.png) [@dulhaver](https://forum.ansible.com/u/dulhaver)\
**Post date:** [April 14, 2024, 7:51pm UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/3 "2024-04-14T19:51:36Z")

</div>

> [@chris](#):
>
> ```auto
> - name: Set a fact for the Nexus version
> ansible.builtin.set_fact:
> nexus_version: >-
> {{ path |
> ansible.builtin.basename |
> ansible.builtin.regex_replace('^nexus-') |
> ansible.builtin.regex_replace('-unix[.]tar[.]gz) }}
> vars:
> nexus_path: /opt/nexus/install/nexus-3.67.1-01-unix.tar.gz
> 
> ```

it’s almost that.

`path` & `nexus_path` need to match in order to make it work. Would you mind to adjust that in your post, so I can mark it as solution?

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [April 15, 2024, 9:20am UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/4 "2024-04-15T09:20:08Z")

</div>

Oops, thanks for spotting the typo.

One other thing that could be optionally added is a [version test](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/version_test.html) in case the file name format changes, eg append something like `| ansible.builtin.version('1.0.0', '>')`.

---

<div class="post-metadata">

**Author:** ![vbotka](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/vbotka/32/359_2.png) [@vbotka](https://forum.ansible.com/u/vbotka)\
**Post date:** [April 16, 2024, 2:46am UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/5 "2024-04-16T02:46:13Z")

</div>

```yaml
path: /opt/nexus/install/nexus-3.67.1-01-unix.tar.gz
nexus_split: "{{ path | basename | split('-') }}"
nexus_path: "{{ nexus_split[0:3] | join('-') }}"
nexus_version: "{{ nexus_split[1:3] | join('-') }}"
nexus_version_major: "{{ nexus_split[1] }}"
nexus_version_minor: "{{ nexus_split[2] }}"

```

gives

```yaml
nexus_path: nexus-3.67.1-01
nexus_version: 3.67.1-01
nexus_version_major: 3.67.1
nexus_version_minor: '01'

```

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [April 16, 2024, 9:44pm UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/6 "2024-04-16T21:44:01Z")

</div>

> [@dulhaver](#):
>
> I am getting a value like `/opt/nexus/install/nexus-3.67.1-01-unix.tar.gz` baked into a variable which I can address via `nexus_tar.path`.
> 
> This results into an unarchived directory later down the line named `/opt/nexus/nexus-3.67.1-01`.

We _just last week_ tackled a very similar problem, but with a complication: the top-level directory of the `.tar.zg` or `.tgz` archives don’t match their files’ `basename`s. Not even close. There’s marketing involved.

So we have to examine the tar archive’s contents to get the correct directory name, like this:

```yaml
    - name: Inspect archive contents for app directory name
      ansible.builtin.shell: |
        set -o pipefail
        tar tf {{ our_app_staging_dir }}/{{ survey_app_tar_file }} | sed -n -e '1s/\/.*//g' -e 1p
      changed_when: false
      register: app_dir_name
      run_once: true # noqa run-once[task]

```

In the course of developing _that_ solution, we hit _another_ problem that someone will surly say is an example of why you should favor modules over shell scripts. And they aren’t exactly wrong.

Our first attempt had a “`head -n 1`” in our pipeline after the `tar` command, but (surprise!) that causes the task to fail! It returns the right data, but `head` quits reading its input stream once it receives enough data to satisfy its parameters. This causes the `tar` process to fail, which triggers the `pipefail` to fail the script. In contrast, `sed` reads the entire stream even though it’s only ever going to print the 1st line. That’s what the “`-e 1p`” does, obviating the need for a `head` process in the pipeline.

I hope someone can benefit from our mistakes. We learned something. (Again, probably.)

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [May 16, 2024, 9:44pm UTC](https://forum.ansible.com/t/extracting-parts-of-a-string/4941/7 "2024-05-16T21:44:10Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
