I had a rather interesting problem come up, and in the process of taking care of it I found what seems to be a bug with 'xargs'. If anyone can explain this to me it would be great. This is a long post, but some may find it interesting. I have a workaround, so I'm not desperate for help, just kinda wondering what went wrong with Plan A.
I have some files (4000+) in various directories on the server with incorrect dates, somehow the years were set wrong. They were all off by the same amount. How that happened is irrelevant. I wanted to use the touch command to correct the year without affecting the month and day. You can try this yourself by creating some files, and some subdirectories with files, etc., and using the touch command to set them to various dates in the 1970's. My files were all in December-February. My test files were given years of 1971, 1975, 1976, and 1979.
Sitting in the upper directory of my test, the following command finds all such files created in the last 32 or so years (12775 days), then displays a full listing, then cuts the list down to the columns showing last modification and full path, then further truncates to only the years I specify.
$ find . -mtime -12775 -depth -type f -print | xargs ls -lat | cut -c46- | egrep ' 197(1|5|6|9) '
Jan 13 1979 ./time/under2/junk5
Dec 31 1976 ./time/under1/junk4
Feb 1 1975 ./time/junk2
Dec 24 1971 ./time/junk1
Dec 24 1971 ./time3
Dec 24 1971 ./time4
Dec 4 1971 ./time/under1/junk3
Feb 14 1971 ./time/under2/junk6
Jan 6 1971 ./time2
So far so good. Let's say all the files need 20 years added to the date. I am not worried about the time of day, so I'll use 12:30 PM for all of them. The touch command would require a format, for the first file, as follows:
touch -ma -t199901131230 ./time/under2/junk5
So I wrote an awk script to convert the dates into the right format as follows:
$ more touchyear20.awk
{
year = $3 + 20
if ($1 ~ /Dec/)
month = 12
else if ($1 ~ /Jan/)
month = 1
else if ($1 ~ /Feb/)
month = 2
else
month = 777
if ($2 <= 9 && month > 9)
print year month "0" $2 "1230 " $4
else if ($2 <= 9 && month <= 9)
print year "0" month "0" $2 "1230 " $4
else if ($2 > 9 && month <= 9)
print year "0" month $2 "1230 " $4
else print year month $2 "1230 " $4
}
and I re-use that earlier command with a couple additions to the pipeline:
$ find . -mtime -12775 -depth -type f -print | xargs ls -lat | cut -c46- | egrep ' 197(1|5|6|9) ' | awk -f touchyear20.awk | xargs -i -t touch -ma -t{}
touch -ma -t199901131230 ./time/under2/junk5
date: bad conversion
touch -ma -t199612311230 ./time/under1/junk4
date: bad conversion
touch -ma -t199502011230 ./time/junk2
date: bad conversion
touch -ma -t199112241230 ./time/junk1
date: bad conversion
touch -ma -t199112241230 ./time3
date: bad conversion
touch -ma -t199112241230 ./time4
date: bad conversion
touch -ma -t199112041230 ./time/under1/junk3
date: bad conversion
touch -ma -t199102141230 ./time/under2/junk6
date: bad conversion
touch -ma -t199101061230 ./time2
date: bad conversion
Obviously it failed. However, I can now cut and paste each of those touch lines and they all run fine, so what is the problem? It seems to be with 'xargs'. My first attempt I actually used xargs like this:
...touchyear20.awk | xargs touch -ma -t
and it of course strung out all my lines on one line with a single touch command, so that all my test files were re-dated Jan 13, 1999 as well as a lot of 0 size files were created with names like 199101061230. Why did that touch command work, but when I correctly pass each line to a separate touch command it fails?
So, if you're up for a challenge try it at home. What I did to get around it is to replace the final pipe to xargs with a "> touch.script". Then I can just execute this file manually and it runs fine. But I really thought it would have been cool to do it all in one command. Oh, well...
btw, HP-UX B.10.20 A 9000/800
-Josh
I have some files (4000+) in various directories on the server with incorrect dates, somehow the years were set wrong. They were all off by the same amount. How that happened is irrelevant. I wanted to use the touch command to correct the year without affecting the month and day. You can try this yourself by creating some files, and some subdirectories with files, etc., and using the touch command to set them to various dates in the 1970's. My files were all in December-February. My test files were given years of 1971, 1975, 1976, and 1979.
Sitting in the upper directory of my test, the following command finds all such files created in the last 32 or so years (12775 days), then displays a full listing, then cuts the list down to the columns showing last modification and full path, then further truncates to only the years I specify.
$ find . -mtime -12775 -depth -type f -print | xargs ls -lat | cut -c46- | egrep ' 197(1|5|6|9) '
Jan 13 1979 ./time/under2/junk5
Dec 31 1976 ./time/under1/junk4
Feb 1 1975 ./time/junk2
Dec 24 1971 ./time/junk1
Dec 24 1971 ./time3
Dec 24 1971 ./time4
Dec 4 1971 ./time/under1/junk3
Feb 14 1971 ./time/under2/junk6
Jan 6 1971 ./time2
So far so good. Let's say all the files need 20 years added to the date. I am not worried about the time of day, so I'll use 12:30 PM for all of them. The touch command would require a format, for the first file, as follows:
touch -ma -t199901131230 ./time/under2/junk5
So I wrote an awk script to convert the dates into the right format as follows:
$ more touchyear20.awk
{
year = $3 + 20
if ($1 ~ /Dec/)
month = 12
else if ($1 ~ /Jan/)
month = 1
else if ($1 ~ /Feb/)
month = 2
else
month = 777
if ($2 <= 9 && month > 9)
print year month "0" $2 "1230 " $4
else if ($2 <= 9 && month <= 9)
print year "0" month "0" $2 "1230 " $4
else if ($2 > 9 && month <= 9)
print year "0" month $2 "1230 " $4
else print year month $2 "1230 " $4
}
and I re-use that earlier command with a couple additions to the pipeline:
$ find . -mtime -12775 -depth -type f -print | xargs ls -lat | cut -c46- | egrep ' 197(1|5|6|9) ' | awk -f touchyear20.awk | xargs -i -t touch -ma -t{}
touch -ma -t199901131230 ./time/under2/junk5
date: bad conversion
touch -ma -t199612311230 ./time/under1/junk4
date: bad conversion
touch -ma -t199502011230 ./time/junk2
date: bad conversion
touch -ma -t199112241230 ./time/junk1
date: bad conversion
touch -ma -t199112241230 ./time3
date: bad conversion
touch -ma -t199112241230 ./time4
date: bad conversion
touch -ma -t199112041230 ./time/under1/junk3
date: bad conversion
touch -ma -t199102141230 ./time/under2/junk6
date: bad conversion
touch -ma -t199101061230 ./time2
date: bad conversion
Obviously it failed. However, I can now cut and paste each of those touch lines and they all run fine, so what is the problem? It seems to be with 'xargs'. My first attempt I actually used xargs like this:
...touchyear20.awk | xargs touch -ma -t
and it of course strung out all my lines on one line with a single touch command, so that all my test files were re-dated Jan 13, 1999 as well as a lot of 0 size files were created with names like 199101061230. Why did that touch command work, but when I correctly pass each line to a separate touch command it fails?
So, if you're up for a challenge try it at home. What I did to get around it is to replace the final pipe to xargs with a "> touch.script". Then I can just execute this file manually and it runs fine. But I really thought it would have been cool to do it all in one command. Oh, well...
btw, HP-UX B.10.20 A 9000/800
-Josh