4

I'm trying to make one command that will take all drives that are not sda and run shred on them and dump the output to a log file. So far I have

find /dev/ -name "sd?" -not -name "sda" -exec [shred -fvz {} > /home/ben/ProjectsInProgress/ShredLogs/$(hdparm -I {} | grep 'Serial\ Number' |cut -f2- -d:).log 2>&1 &] \;

As you can see, I have gotten a fair distance into this with searching google, but now i ran into something I don't know what to do because the output I got is

[1] 13097
{}: No such file or directory
]: command not found
[1]+  Exit 1                  find /dev/ -name "sd?" -not -name "sda" -exec [shred -fvz {} > /home/ben/ProjectsInProgress/ShredLogs/$(hdparm -I {} | grep 'Serial\ Number' |cut -f2- -d:).log 2>&1

Does anyone have a suggestion?

Also, I am currently working on this problem but suggestions would be nice. When I run

shred -fvz /dev/sdb > /home/ben/ProjectsInProgress/ShredLogs/$(hdparm -I /dev/sdb | grep 'Serial\ Number' |cut -f2- -d:).log 2>&1

I get an ambiguous redirect error.

2 Answers 2

2

EDIT: Though the original answer tells you part of why your find command didn't work, the loop using find won't work for USB HDDs. Scroll to the bottom of the answer for a better version.

Note that the logging won't work at all with USB flash drives; hdparm is only for HDDs.


Your find command won't work. At all. Why?

There are a few problems, but the major one is this: The -exec option looks in the PATH for an executable with the name of its first argument and executes it with any other arguments to find up to a semicolon. It does not pass its arguments to a shell, which means using $(...), redirection, etc will not work.

How do you fix this? There are a few ways.

The most obvious might be to pass your command to a shell:

find . -name testing12345 -exec bash -c '...$(...)... > /path/to/some/file 2>&1' \;

Yes, this works, but in a complicated expression with multiple types of quotes, escaping can quickly become a nightmare.

Often, using a loop is the easiest way to do this. Since you already have a working find command, the easiest way to do this is to take the -exec arguments off of it and pipe it into a loop:

find (your find arguments here) -print0 | while IFS= read -r -d $'\0' filename; do
    # process "$filename"
done

IFS= and the -print0 and -d $'\0' options to find and read avoid problems with newlines in file names. The -r option ensures that read doesn't process backslashes in the file names.

Combining that and fixes to your other problems, we get this, which seems to work:

find /dev/ -name "sd?" -not -name "sda" -print0 | while IFS= read -r -d $'\0' filename; do
    if (hdparm -i "$filename" > /dev/null 2>&1); then
        shred -fvz "$filename" > /home/ben/ProjectsInProgress/ShredLogs/$(hdparm -i "$filename" | grep -o 'SerialNo=\S*' |cut -f2 -d=).log 2>&1 &
    fi
done

I've only tested it myself with an echo statement in place of shred since I don't want to shred my disks, so please tell me if it works.


EDIT: The find version is broken for USB HDDs. This modified version that uses lsblk works correctly:

lsblk -ld | grep -o '^sd[b-z]' | while read -r filename; do
    filename="/dev/$filename"
    shred -fvz "$filename" > "/home/ben/ProjectsInProgress/ShredLogs/$(hdparm -I "$filename" | grep -o 'Serial Number:\s*\S*' | cut -f2 -d: | sed 's/^\s*//').log" 2>&1 &
done
7
  • @BenStumpf What error did it give (or did it give no error but do nothing)? while IFS= read -r -d $'\0' filename reads in the filenames piped to the loop from find, seperating them by null bytes (the -print0 option tells find to seperate the files it outputs by null bytes) and processes them one by one. Sep 15, 2016 at 17:25
  • Ok, thank you for the explanation. The script did nothing. if i remove the if statement i get the ambiguous redirect error
    – Ben Stumpf
    Sep 15, 2016 at 17:28
  • @BenStumpf It didn't even create a log file? That's odd. You ran it in a root shell, right? Sep 15, 2016 at 17:38
  • yes i ran it as root and no it did not make the log files
    – Ben Stumpf
    Sep 15, 2016 at 17:40
  • The script now does nothing
    – Ben Stumpf
    Sep 15, 2016 at 17:50
2

This script should do what you want. Note that it must run as root!

#!/bin/bash
logpath="/home/ben/ProjectsInProgress/ShredLogs"
lsblk -l | grep -o '^sd[b-z] ' | while read f; do
    logfile="$logpath/$(hdparm -i "/dev/$f" | grep -oP "(?<=SerialNo=)\w+")"
    shred -fvz "$f" &> "$logfile"
done

Thanks to @terdon for providing this improved (and hopefully now fixed) version.

Please tell me whether it works, I'm not really motivated to test shredding my own disks...

1
  • Comments are not for extended discussion; the entire conversation that was taking place here has been moved to chat.
    – Thomas Ward
    Sep 16, 2016 at 15:17

You must log in to answer this question.

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