Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm writing these direct on the forum, no syntax highlight, no Ctrl+p ( vim ; )
I do that myself sometimes. It usually results in multiple edits.
BTW, have you considered the possible implications of this:
Quote:
Originally Posted by Firerat
Code:
Dirs=( ${DirPath%/}/*/ )
Under some circumstances (not in these particular scripts, though, due to the loop) performing an rm -r on the resulting variable $Dir might have a, shall we say, interesting effect.
It makes me shudder whenever someone appends a "/" behind a variable used to hold a path or filename marked for deletion. I think the person who wrote the (un)installer for the Bungie game "Myth II" back in 1998 might have done just that.
if that command line was too long we can cd DirPath first. If it was still too long we can try xargs
Not to be beating a dead horse or anything, but what's the advantage of that code as opposed to this:
Code:
#!/bin/sh
DirPath=/share/CACHEDEV1_DATA/Backup/NetBakData/User/
Keep=4
ls -1dtr "${DirPath}*" | head -n -${Keep} | xargs rm -r
This is measurably faster, a lot simpler (in my opinion), and it has the advantage of not relying on specific directory names. Instead, it keeps the four most recent directories based on timestamps, which is really what the OP asked for.
(Honest question.)
Edit: Yes, this also contains a variant of the "empty path" vulnerability, but you'd have to manually type in a blank or wrong path for it to fail.
Last edited by Ser Olmy; 10-16-2019 at 12:14 PM.
Reason: Quotes around paths are nice
Not to be beating a dead horse or anything, but what's the advantage of that code as opposed to this:
Code:
#!/bin/sh
DirPath=/share/CACHEDEV1_DATA/Backup/NetBakData/User/
Keep=4
ls -1dtr ${DirPath}* | head -n -${Keep} | xargs rm -r
This is measurably faster, a lot simpler (in my opinion), and it has the advantage of not relying on specific directory names. Instead, it keeps the four most recent directories based on timestamps, which is really what the OP asked for.
(Honest question.)
That is an interesting example, because now your code is more readable (and a lot simpler), yes. But I do not think it is faster. How did you measure that?
And - if the filenames (dirnames) contain spaces it will not work properly.
I do that myself sometimes. It usually results in multiple edits.
BTW, have you considered the possible implications of this:
Under some circumstances (not in these particular scripts, though, due to the loop) performing an rm -r on the resulting variable $Dir might have a, shall we say, interesting effect.
It makes me shudder whenever someone appends a "/" behind a variable used to hold a path or filename marked for deletion. I think the person who wrote the (un)installer for the Bungie game "Myth II" back in 1998 might have done just that.
yeah, tests should be done
i.e. if ${DirPath} exists ( and is not / )
This is going to be a problem regardless
one reason I had the echo in there
That is an interesting example, because now your code is more readable (and a lot simpler), yes. But I do not think it is faster. How did you measure that?
I generated 100,000 directories (seq 0 1 99999 | xargs mkdir) and ran a test on an old server.
Turns out populating an array with that many elements takes a non-trivial amount of time. This is arguably irrelevant if the number of directories is anything but huge, but the point is that this makes the script a tiny bit slower, while the initial argument for using an array had to do with speed.
Quote:
Originally Posted by pan64
And - if the filenames (dirnames) contain spaces it will not work properly.
You're right, there has to be double quotes around the parameter to the ls command; I'll fix that.
Of course, I could argue that the OP's directory structure doesn't have directories with spaces, but then I just made the argument that the solution ought to be more generic, so... mea culpa.
Edit: And I just realized that this is an overly simplistic solution, vulnerable to precisely the same issues that I've been arguing against. Mea maxima culpa, I guess.
pan64 had the right idea:
Quote:
Originally Posted by pan64
if that command line was too long we can cd DirPath first.
That gets rid of the parameter expansion to the ls command, and provides an extra sanity check to boot.
Revised version:
Code:
#!/bin/sh
DirPath=/share/CACHEDEV1_DATA/Backup/NetBakData/User
Keep=4
cd "$DirPath" || exit 1
ls -1tr | head -n -${Keep} | xargs rm -r
I don't think either of the two pipelines work. You create a long listing and pass filenames like drwxrwxrwx or admin to the rm command. Try without the -l option.
EDIT: The rm -f option prevents error messages to be printed, so that it should actually work (though it's not pretty).
Hi, actually works fine:
Code:
[~] # cd /share/CACHEDEV1_DATA/Backup/NetBakData/User
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] # ls
2019-10-07-11-30-00/ 2019-10-09-11-30-00/ 2019-10-15-11-30-00/
2019-10-08-11-30-00/ 2019-10-14-11-30-00/ 2019-10-16-11-30-00/
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] # ls -lt | tail -n+4
drwxrwxrwx 3 admin administ 4096 Oct 9 11:30 2019-10-09-11-30-00/
drwxrwxrwx 3 admin administ 4096 Oct 8 11:30 2019-10-08-11-30-00/
drwxrwxrwx 3 admin administ 4096 Oct 7 11:29 2019-10-07-11-30-00/
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] # ls -lt | tail -n+4 | xargs rm -rf
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] # ls
2019-10-14-11-30-00/ 2019-10-15-11-30-00/ 2019-10-16-11-30-00/
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] #
Without -l, same results:
Code:
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] # ls
2019-10-07-12-00-00/ 2019-10-09-12-00-00/ 2019-10-14-12-00-00/ 2019-10-16-12-00-00/
2019-10-08-12-00-00/ 2019-10-11-12-00-00/ 2019-10-15-12-00-00/
[/share/CACHEDEV1_DATA/Backup/NetBakData/User] # cd
[~] # ls -t /share/CACHEDEV1_DATA/Backup/NetBakData/USer| tail -n+4 | xargs rm -rf
[~] # ls /share/CACHEDEV1_DATA/Backup/NetBakData/User
2019-10-07-12-00-00/ 2019-10-09-12-00-00/ 2019-10-14-12-00-00/ 2019-10-16-12-00-00/
2019-10-08-12-00-00/ 2019-10-11-12-00-00/ 2019-10-15-12-00-00/
/tmp/test$ sync ; time ( bash ../pipes.sh; sync )
real 0m2.631s
user 0m0.532s
sys 0m2.201s
Yes, the numbers for the first test are accurate; I could hardly believe it myself, and ran the test several times to confirm.
Hardware: The server used is an elderly Fujitsu Primergy RX300 S8 with a single 6-core Xeon E5-2620 v2 CPU running at 2.1 GHz, with 64 Gb DDR3 RAM. The drive array is a 12 Tb 4-drive RAID5 SAS array driven by an LSI MegaRAID SAS 2108 controller.
The server was otherwise totally idle during the tests.
Last edited by Ser Olmy; 10-16-2019 at 01:53 PM.
Reason: added some more hardware details
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.