0

Is there a way to split this line on the last _ to create two variables?

The folder in Linux is of the form Project_Data1_xxx or Project_Data1_Sub1_xxx. I would like to create two variables :

  1. for the first two or three octets
  2. for what comes after the last _.

I have spent quite a bit of time on this and apologize as I am new to Linux and I am not yet understanding all the differences between windows and linux.

Question: do I break it up into two statements to get the front and the back?

I am doing ls -1 of a folder into a variable. So I do

#!/bin/bash
srcIn=/scripts/server1
dstIn=/scripts/server2
data=test

sourcein=$(ls $srcIn/ | grep $data)
destinationin=$(ls $dstIn/ | grep $data)

I then get:

echo $destinationin 
test_data1_xxx test_data2_xxx test_data3_xxx

echo $sourcein 
test_data1_ccc test_data2_ccc test_data3_ccc

In the end. I need to create a copy line that goes:

cp /test_data1_ccc/* /test_data1_xxx
cp /test_data2_ccc/* /test_data2_xxx

and so on... There may be 2 or 3 underscores but the format is always the same.

The strings xxx and ccc could be abc123 or ccc567 and do not necessarily have the same number of characters. The one thing that doesn't change is the only difference in the two locations is what follows the last _ - but they will always be different.

kvantour
  • 25,269
  • 4
  • 47
  • 72

1 Answers1

3

I would do it in two steps. Assuming that the string is inside a variable:

name=Project_Data1_xxx
$ echo ${name%_*}
Project_Data1
$ echo ${name##*_}
xxx
  • ${var%foo} removes the shortest occurrence of foo from the end
  • ${var##foo} removes the longest occurrence of foo from the start

These parameter expansions can be combined with the wildcard * to remove anything, rather than a string literal.

In the context of your script, I would suggest something like this:

for input_dir in /scripts/server1/*data*/; do
    base=${input_dir%_*}                 # trim the last part
    base=${base##*/}                     # trim the leading part
    dest=( /scripts/server2/"$base"*/ )  # find the destination dir
    if [[ ${#dest[@]} -eq 1 ]]; then
        cp "$input_dir"* "${dest[0]}"
    else
        echo "${#dest[@]} destination paths found, expected 1"
    fi
done
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • it is so close: I changed *data* to test* because that is what I am searching on and I get: cp: cannot stat '/scripts/server1/test_data1_ccc//*': No such file or directory cp: cannot stat '/scripts/server1/test_data2_ccc//*': No such file or directory cp: cannot stat '/scripts/server1/test_data3_ccc//*': No – Larry Van Brunt Apr 11 '18 at 15:53
  • I removed the extra slash after `"$input_dir"` in the `cp` line. – Tom Fenech Apr 11 '18 at 16:09