Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Using Linux Centos 6

I have 16 years of data sorted in directories by year and then day (1997/001, 1997/002...). Each 'day' directory has 24 files, 1 for each hour, with hour name in each file (i.e. 1997.001.00.bin, 1997.001.01.bin...1997.001.23.bin).

I can't change the filename or the algorithm used to name the files. I have a script that reads the meta data in the file and archives it into the correct year/day directory. However, the first file of each day actually begins at 23:59:59. So that first file of each day actually gets archived on the previous day. 1997.001.00.bin actually gets archived in 1996/365 directory.

I need to generate symlinks so that the a link for 1997.001.00.bin resides in 1997/001 and points to the actual location in 1996/365. If it were only a few files, I'd just run the command by hand, but I need to do this for 5000+ files. Any help on generating some commands for a script would be greatly appreciated.

share|improve this question
    
Is the file correctly named? I mean is the first file of 1997 actually 1996/365/1997.001.00.bin? Or is it 1996/365/1996.001.00.bin or something? –  terdon Sep 2 '13 at 3:35

2 Answers 2

Run this in the directory that holds 2012, 2013, etc.

find * -type f -name "*bin" -exec sh -c 'ln -s ../../{} `echo {} | sed -r '\''s,.*/([0-9]+)\.([0-9]+).*,\1/\2,'\''`' \;

It finds *bin files that are regular files, not symlinks, and creates a symlink for each of them in the right directory. It can be run multiple times without issue, say after new *bin files are created, though you will get errors like ln: failed to create symbolic link ‘2013/002/2013.002.00.bin’: File exists. These can be ignored.

share|improve this answer
    
I don't understand what you are trying to do here. Your command will run things like ln -s ../../1996/067/1996.067.19.bin 1996/067. 1) The file ../../1996/067/1996.067.19.bin will never exist, why the ../../? 2) You are linking all files, not just the one in the wrong directory. 3) Even if you did get part 1) right, you still would be linking the same file to itself, your sed command is just printing the same year and day as in the original file name. –  terdon Sep 2 '13 at 3:58
    
1) That is the string put into the symlink, which is in one of the month directories, so yes, ../../1996/067/1996.067.19.bin does exist. 2) It will just fail with File exists for ones in the right directory. 3) When files are in the wrong directory, it creates a symlink to them in the right directory. If the second parameter to ln is a directory, it will create the symlink in that directory, using the basename of the reference. –  wingedsubmariner Sep 2 '13 at 4:06
    
@teardon: I tested this before posting, and can guarantee that it works. –  wingedsubmariner Sep 2 '13 at 4:06
    
So did I and it didn't :). Add an echo to the beginning of the exec and you'll see. It will print out a long list of commands like the example I gave in my previous comment. As you can see there, you are not changing directories, even if you are right about the ../../ and I still don't see why you think so, it would still be pointing to a directory of the same name. As far as I an tell, the OP needs to link 1996/365/1997.001.00.bin to 1997/001/1997.001.00.bin and you are linking ../../1996/365/1997.001.00.bin to 1996/365/1997.001.00.bin. –  terdon Sep 2 '13 at 4:11
    
We aren't changing directories. The symlink itself needs to contain ../../, he needs a symlink 1996/365/1997.001.00.bin that contains ../../1997/001/1997.001.00.bin, which is what this command does. –  wingedsubmariner Sep 2 '13 at 4:23

If the mis-archived file is correctly named, this should work (just paste it into a terminal in the parent directory):

nxtyear="";
tmrow="";
for year in $(seq 2012 -1 1996); do 
 for day in $(seq -f "%03g" 365 -1 1); do 
  [ -d $year/$tmrow ] && 
  ln -s ../../$year/$day/$nxtyear.$tmrow.00.bin $nxtyear/$tmrow/;
  tmrow=$day;
  nxtyear=$year;
 done; 
done

This assumes that the first file of 1997 is at 1996/365/1997.001.00.bin. In other words, that it is correctly named but incorrectly placed. If this is not the case, let me know and I'll modify my answer.


Explanation

The little script above will cycle through every year from 2012 to 1996 backwards, and likewise for all numbers from 365 to 001. At the end of its loop, it saves the current day as $tmrow and the current year as $nxtyear. The first time it runs, these will be undefined and the script will do nothing (that's why I'm checking if the directory exists with [ -d $year/$tmrow ] &&).

Every time the script loops, it will link a file called $year/$day/$nxtyear.$tmrow.00.bin to $nxtyear/$tmrow/. So, for example, when $year is 1996, and $day is 365, $nxtyear will be 1997 and $tmrow will be 001. The script will therefore run

 ln -s 1996/365/1997.001.00.bin 1997/001/

You can check what the script will do without having it make any changes by adding echo to the ln line:

[ -d $year/$tmrow ] && 
echo ln -s $year/$day/$nxtyear.$tmrow.00.bin $nxtyear/$tmrow/;
share|improve this answer
    
This script doesn't work: the symlinks it creates cannot be followed. See our comments in my answer, you need to include a ../../ in your symlinks. Try doing a cat on one of the symlinks and you can see it goes nowhere. –  wingedsubmariner Sep 2 '13 at 4:27
    
@wingedsubmariner no it doesn't, you're right again. It should work now, but I'll test tomorrow. –  terdon Sep 2 '13 at 4:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.