1

I have lots of .dat file and I want to convert them to .sac file (a type of seismogram file). I convert files with xy2sac program (I didn't write the code), but I have to give converted files a new name which I pick.

The converter code works like this:

xy2sac filename.dat newfilename.sac

What I want to do is giving my new file names while xy2sac program is working in a loop. For example my dat file names are like this:

BRGA_KO_disp_post_mij_conv0000_E.dat
BRGA_KO_disp_post_mij_conv0000_E.dat
BRGA_KO_disp_post_mij_conv0000_N.dat
BRGA_KO_disp_post_mij_conv0000_Z.dat
GADA_KO_disp_post_mij_conv0000_E.dat
GADA_KO_disp_post_mij_conv0000_N.dat
GADA_KO_disp_post_mij_conv0000_Z.dat
HYBL_KO_disp_post_mij_conv0000_E.dat
HYBL_KO_disp_post_mij_conv0000_N.dat
HYBL_KO_disp_post_mij_conv0000_Z.dat
ISK_KO_disp_post_mij_conv0000_E.dat
ISK_KO_disp_post_mij_conv0000_N.dat
ISK_KO_disp_post_mij_conv0000_Z.dat
TUZL_KO_disp_post_mij_conv0000_E.dat
TUZL_KO_disp_post_mij_conv0000_N.dat
TUZL_KO_disp_post_mij_conv0000_Z.dat

I want to change their name to:

BRGA_KO__E.sac
BRGA_KO__E.sac
BRGA_KO__N.sac
BRGA_KO__Z.sac
GADA_KO__E.sac
GADA_KO__N.sac
GADA_KO__Z.sac
HYBL_KO__E.sac
HYBL_KO__N.sac
HYBL_KO__Z.sac
ISK_KO__E.sac
ISK_KO__N.sac
ISK_KO__Z.sac
TUZL_KO__E.sac
TUZL_KO__N.sac
TUZL_KO__Z.sac

So I would like the pick first 8 characters and last character before the .dat.

How can I achieve that?

I use this loop but it didn't work, and I end up with .dat file extension.

foreach file (`ls *.dat*`)
xy2sac *.dat *.sac << END
END
end

Thanks in advance.

3 Answers 3

2

If you really can't change to a saner shell, then in csh, you can use the :s modifier to make string substitutions within variables

Ex.

#!/bin/csh -f

foreach file ( *.dat )
echo xy2sac $file $file:s/disp_post_mij_conv0000//:s/.dat/.sac/
end

Remove the echo once you are happy that the filenames are correct

1
  • Thank you so much !!! You are a hero, it works !!!
    – curious
    Oct 9, 2019 at 17:58
0

Caveat: I didn't realize that you're using csh, so my answer applies to bash only. If that's not an option, the other answers provide usable solutions.

You can use the =~ operator together with the BASH_REMATCH array to match parts of a filename and combine them to the new filename:

#!/bin/bash
for file in *.dat
do
    if [[ $file =~ ([A-Z]+_[A-Z]+_).*(..)\.dat ]]
    then
        xy2sac $file ${BASH_REMATCH[1]}${BASH_REMATCH[2]}.dac
    fi
done

On a side note, you should make sure that your requirements and example match so we don't have to guess what you actually mean, it's unclear of you really need to feed an empty here-document into the command. I have built the code to match your example, but apparently the first part to match isn't always 8 characters, and you meant the last two characters before .dat (including _,) not the last one only.

3
  • @steeldriver Oops, sorry I overlooked that. Long time since I touched a csh. In this case my answer is not applicable, of course. Oct 9, 2019 at 11:37
  • 1
    IMHO it's still applicable - if fully changed to bash Oct 9, 2019 at 11:40
  • @Hans-MartinMosner you are right about character number its is not clear, but I think what I want to do is clear :) Also as you said it didn't work in cshell. Thanks anyway for replying and giving your time.
    – curious
    Oct 9, 2019 at 18:08
0

A proposal: use awk to easily cut on "_" and "." and get easily access the parts you want to construct the new filename with

If you are sure all the *.dat files have the exact structure you mentionned (ie, no spaces in it, always 6 '_' and only 1 '.', etc):

# solution with awk, which can easily define fields using a regex
# (here: "[_.]" so that either 1 "_" or 1 "." separates one field from the next)
# awk will check we presented a filename with the correct number of fields, and also

cd /correct/directory || exit 1   # ie, go to the right directory containing your .dat files, or exit
find ./ -name '*.dat' -print \
  | awk -F'[_.]' -v nbfield=8 '
       ( NF != nbfield ) {
           print "Error: file " $0 " ignored: does not have the right structure." ; 
           next;
       }
       ( NF == nbfield ) { 
           print "converting file: " $0 " ..."
           system("echo _remove_echo_when_ok_ xy2sac  " $0 "  " $1"_"$2"__"$(NF-1)".sac && echo OK || echo ___ko___ ") 
       }
     '

And of course, when you think it is correctly working: replace "echo _remove_echo_when_ok_ xy2sac " (that only displays but doesn't execute the xy2sac) with "xy2sac " (that will execute it)

8
  • I tried your code but it says that >>> Unmatched '''.
    – curious
    Oct 9, 2019 at 18:19
  • @curious: that's... curious ^^ It works for me. You should maybe just copy-paste the above code, to avoid mistyping? (and when it seems to work fine, remove just the first echo _...._ , and not the 2 after that shows ok / _ko_ ) Oct 10, 2019 at 9:24
  • @curious: and I changed it : $7 contains the "E" part, instead of $6 Oct 10, 2019 at 9:32
  • I tried your code again but I got this error which you put in the code just an example of error ; Error: file ./BRGA_KO_disp_post_mij_conv0000_E.dat ignored: does not have the right structure." I think its causing from my file names because I put in it wrong way to say just first 8 characters . Because some of them are less than 8. Thanks for your kind help and giving your time :)
    – curious
    Oct 12, 2019 at 8:16
  • @curious you can adapt the script for those: change $7 into $(NF-1) and adjust the value of fields to cover those ignored Oct 12, 2019 at 15:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .