-1

Array longestPaths contains directory paths. I want to loop through them and remove their first 3 directories. For example, given the following array items in longestPaths:

/foo/bar/dir1/log/2020/02
/foo/bar/dir2/log/2020/01
/foo/bar/dir3/log/2019/12

I want the other array contain the following values after looping through and modifying items in longestPaths:

/log/2020/02
/log/2020/01
/log/2019/12

How could I do this in bash (or awk)? Thank you

kamokoba
  • 497
  • 9
  • 17
  • 2
    On SO we do encourage users to add their efforts which they have put in order to solve their own problems so please do add so(not a down voter). – RavinderSingh13 Feb 24 '20 at 10:12
  • didn't know that, sorry. I thought we are allowed to ask any programming-related question without necessary putting any research effort, like for example this one --> https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python?rq=1 – kamokoba Feb 24 '20 at 10:24
  • 2
    It is advised by community as well as by experts to add efforts in questions. If you see closing a question has option where it says(asking for debugging help or info is not there etc etc). Since we all are here to learn it is recommended to add efforts by OP(original poster). – RavinderSingh13 Feb 24 '20 at 10:33

2 Answers2

3

Solution1 with a loop:

Exactly altering the entries of the longestPaths array, as you asked for:

#!/bin/bash

# Populate longestPaths with sample data
declare -a longestPaths=(
  '/foo/bar/dir1/log/2020/02'
  '/foo/bar/dir2/log/2020/01'
  '/foo/bar/dir3/log/2019/12'
)

# Loop through indexes of the longestPaths array
for i in "${!longestPaths[@]}"; do
  # RegEx match entry at index to extract the short path
  [[ "${longestPaths[i]}" =~ \/log\/[[:digit:]]{4}\/[[:digit:]]{2}$ ]]

  # Replace the entry with its shortened version from the RegEx match
  longestPaths[i]="${BASH_REMATCH[0]}"
done

# Debug Print the modified longestPaths array
typeset -p longestPaths

Output:

declare -a longestPaths=([0]="/log/2020/02" [1]="/log/2020/01" [2]="/log/2019/12")

Solution2 using a Bash4 (with mapfile support):

Here it does not loop, but use Gnu grep to process the input array entries as null-delimited records.

#!/bin/bash

# Populate longestPaths with sample data
declare -a longestPaths=(
  '/foo/bar/dir1/log/2020/02'
  '/foo/bar/dir2/log/2020/01'
  '/foo/bar/dir3/log/2019/12'
)

# Declare a destination array of shortest paths
declare -a shortestPaths

# Map the null-delimited output of grep to the shortestPath array
mapfile -d '' shortestPaths < <(
  # Stream the null-delimited longestPaths array entries to grep
  printf '%s\0' "${longestPaths[@]}" |\
  grep \
    --null-data \
    --only-matching \
    --extended-regexp \
    --regexp='\/log\/[[:digit:]]{4}\/[[:digit:]]{2}$'
)

# shellcheck disable=SC2034 # Debug Print the shortestPaths array
typeset -p shortestPaths

Output:

declare -a shortestPaths=([0]="/log/2020/02" [1]="/log/2020/01" [2]="/log/2019/12")
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
1

What you have as an example, this should work.

#!/usr/bin/env bash

shopt -s extglob

longestpath=(
    /foo/bar/dir1/log/2020/02
    /foo/bar/dir2/log/2020/01
    /foo/bar/dir3/log/2019/12
    /foo/bar/dir51/log/2019/12
    /foo/bar/dir10000/log/2019/12
    /foo/bar/dir99999999999999999999999999999/log/2019/12
)


printf '%s\n' "${longestpath[@]##*dir+([[:digit:]])}"

Output

/log/2020/02
/log/2020/01
/log/2019/12
/log/2019/12
/log/2019/12
/log/2019/12
  • I have added some long numeric strings in the array elements, just to show that regardless how many digits after dir the glob should work as expected.
  • Like what i have said if the path name is constant e.g. it has dir followed by numeric/digit strings then that should work.
Jetchisel
  • 7,493
  • 2
  • 19
  • 18