LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Using BASH to Rename files with last mod date using stat & awk (http://www.linuxquestions.org/questions/programming-9/using-bash-to-rename-files-with-last-mod-date-using-stat-and-awk-917480/)

Liquid_Squelch 12-06-2011 08:16 PM

Using BASH to Rename files with last mod date using stat & awk
 
I've seen solutions for this question before, but for whatever reason, I'm not able to get it to work on my opensuse machine.

I have a directory of files (website daily backup) that I want to rename with their create (modified) date and save them off to a new directory.

The new directory has the base file name, and for now, that step has been removed from the script.

Basically, take the file which will be called via a variable on the command line, find the modified date, and rename the file to include the modified date as part of the file name.

The code I have is below. I can get the base file name, but my mod_date does not return anything, so I get files saved as "base_.ext"

Any one have any solutions? The file I am trying to rename does exist. I did a 'touch filename.tst' to create "filename.tst"
Thanks

commandline to launch would be: ./rename.sh file

Code:

#!/bin/bash

# Backup with stat date

# File prefix
file=${1}

# Rename the file with the modified date
stat -c %y ${file}.tst | mod_date="awk '{print $1}'" | cp ${file}.tst ${file}_${mod_date}.txt ;


Chirel 12-07-2011 03:27 AM

Hi,

When you do

Code:

# Rename the file with the modified date
stat -c %y ${file}.tst | mod_date="awk '{print $1}'" | cp ${file}.tst ${file}_${mod_date}.txt ;

I guess what you really want is to do that :

Code:

# Copy the file with the modified date
mod_date="$(stat -c %y ${file}.tst | awk '{print $1}')"
cp ${file}.tst ${file}_${mod_date}.txt

Then use mv when you are ready.

Reuti 12-07-2011 01:52 PM

Quote:

Originally Posted by Chirel (Post 4544091)
Code:

# Copy the file with the modified date
mod_date="$(stat -c %y ${file}.tst | awk '{print $1}')"
cp ${file}.tst ${file}_${mod_date}.txt


As the mod_date is an assigned variable, it should be possible to strip off the unwanted information by bash’s parameter expansion:
Code:

# Copy the file with the modified date
mod_date=$(stat -c %y ${file}.tst)
cp ${file}.tst ${file}_${mod_date%% *}.txt

Or assign it to an array and use the first element as it’s split by a space character already:
Code:

# Copy the file with the modified date
mod_date=($(stat -c %y ${file}.tst))
cp ${file}.tst ${file}_${mod_date}.txt


David the H. 12-07-2011 04:45 PM

Code:

stat -c %y ${file}.tst | mod_date="awk '{print $1}'" | cp ${file}.tst ${file}_${mod_date}.txt ;
Chirel has already showed the correct way to write this, but I'm going to explain why.

The "|" pipe feeds the stdout of one command into the stdin of the next. This means you need to make sure that the commands you use write & read to each other properly.

The stat command at the beginning is ok. It sends its output to stdout. But looking at the second command...

Code:

mod_date="awk '{print $1}'"
While awk does read from stdin, you aren't actually running awk here. All you're doing is setting the variable "mod_date" to the literal string "awk '{print $1}'".

So there's no command here that reads from stdin.

To set a variable from a command you need to use a command substitution, which is "$()"
Code:

stat -c %y ${file}.tst | mod_date=$( awk '{print $1}' )
That's a little better, but now we have a problem in that commands in pipes run as subshells. Variables are only available inside the shells they are set in (and child processes of the same), and so mod_date is lost as soon as the command terminates.

But we don't really want to set a variable yet anyway. If we capture the output to a variable, then there's nothing for the next command in the chain to read. So lets remove that and just use awk directly.

Code:

stat -c %y ${file}.tst | awk '{print $1}'
awk now prints to stdout, which becomes the stdin of the next command. However...

Code:

cp ${file}.tst ${file}_${mod_date}.txt
cp is not a command capable of reading from stdin, so it just ignores the input from the rest of the chain. And we don't have a mod_date variable to use anyway, so the command fails. So what do we do?

Well, we capture the output of the stat+awk chain as a whole into a variable, then we subsequently run cp using it. And that's the solution what Chirel supplied.


Finally, as Reuti demonstrated, It's possible to replace awk with bash's built-in parameter substitution.


I advise you to take some time and read through the Bash Guide here before continuing on. It covers all the basic concepts you need to know:

http://mywiki.wooledge.org/BashGuide

The FAQ and Pitfalls pages in particular are also extremely useful:

http://mywiki.wooledge.org/BashFAQ
http://mywiki.wooledge.org/BashPitfalls

Liquid_Squelch 12-11-2011 06:27 PM

Thank you all for the help. The solutions offered helped - and I certainly appreciate the explanation from David the H. It is one thing to copy an answer into the script (which works), but it is another to understand how and why it works.

Thanks again to all who replied..


All times are GMT -5. The time now is 07:38 AM.