0

I have this part of a script which worked for a couple of weeks, but now stopped working:

find /media/2C1F-444F/usb_musik/newMusik -type f -printf '%T+ %p\n' | sort | head -n 5 |  awk '{print $2}'  | xargs sudo rm -v

It will find in the path files print a list sorted by oldest first and show only 5 and then delete them.

Now the output is

rm: cannot remove /media/2C1F-444F/usb_musik/newMusik/N/Neil: No such file or directory

I changed a bit the code in awk print $2 changed to $3

find /media/2C1F-444F/usb_musik/newMusik -type f -printf '%T+ %p\n' | sort | head -n 5 |  awk '{print $3}'  | xargs sudo rm -v

which throws the error:

rm: cannot remove Young/Mirror_Ball/09.Throw_Your_Hatred_Down.flac: No such file or directory

Checking on the directory, the files are there and are the oldest so should be ok to delete.

How is it possible that a script does not work any more? On the device the script stay where not update or upgrade done!

After deleting manually the files and started the command again (the first with awk $2) deleting worked again. The difference is the space in the path were it did not work - the second have underline and it rm, but not sure if it have to do with this.

removed '/media/2C1F-444F/usb_musik/newMusik/_VA/Australien/Various-Hits_From_Down_Under/09.Jimmy_Barnes-It_Will_Be_Alright.flac'
removed '/media/2C1F-444F/usb_musik/newMusik/_VA/Australien/Various-Hits_From_Down_Under/10.Air_Supply-All_Out_of_Love.flac'
1
  • 5
    Your code cannot handle spaces in directory names. Commented Sep 28 at 21:29

3 Answers 3

2

The best way to handle special characters in file paths is to use null terminated lists; a feature supported by many standard Linux tools

find /home/lmc/tmp/abc/ -type f -printf '%T+ %p\0' | \
sort -z | head -z -n5 | cut -z -c 32- | xargs -r0 rm -v

find ... -printf '%T+ %p\0'
sort -z
cut -z
xargs -r0

Result

removed '/home/lmc/tmp/abc/with space/10574705_780745301964694_1921917122_n.png'
removed '/home/lmc/tmp/abc/with space/10689463_10204933967012054_5293239505955413653_n.jpg'
removed '/home/lmc/tmp/abc/with space/10940622_852091444848970_5646746288209785678_n_002.jpg'
removed '/home/lmc/tmp/abc/with space/10940622_852091444848970_5646746288209785678_n.jpg'
removed '/home/lmc/tmp/abc/with space/10956906_449528018528925_457296511_n.png'
Sign up to request clarification or add additional context in comments.

1 Comment

You don't have to hardcode the length of timestamps. cut -z -d ' ' -f 2- will work
1

As mentioned in comments, your code is not able to correctly handle directory (and file) names that contain spaces. And since awk's default field separator includes spaces, your awk script sees your full paths as multiple fields ($2, $3, ...).

Since you have the ability to designate the field delimiter (via find/printf) one simple fix would be to pick a delimiter you know won't show up in your directory (and file) names.

For example, assume | does not show up in directory (or file) names then we can make 3 small changes:

OLD: find /media/2C1F-444F/usb_musik/newMusik -type f -printf '%T+ %p\n' | sort | head -n 5 |  awk        '{print $2}'  | xargs       sudo rm -v
NEW: find /media/2C1F-444F/usb_musik/newMusik -type f -printf '%T+|%p\n' | sort | head -n 5 |  awk -F '|' '{print $2}'  | xargs -I {} sudo rm -v {}
                                                                  ^                                ^^^^^^                       ^^^^^            ^^

Where:

  • printf '%T+|%p\n' - use | as delimiter between timestamp and path to file
  • awk -F '|' - tell awk to treat | as the field delimiter
  • xargs -I {} sudo rm -v {} - tell xargs to (effectively) not split the input on spaces (akin to wrapping the path/file combo in quotes)

Taking for a test drive:

$ cd /home/username/tmp
$ mkdir -p 'this dir/that dir'
$ touch 'this dir'/file1.txt 'this dir/that dir/file2.txt'

$ find "$tmpdir/testd" -type f -printf '%T+|%p\n' | awk -F'|' '{print $2}'
/home/username/tmp/testd/this dir/file1.txt
/home/username/tmp/testd/this dir/that dir/file2.txt

$ find "$tmpdir/testd" -type f -printf '%T+|%p\n' | awk -F'|' '{print $2}' | xargs -I {} sudo rm -v {}
removed '/home/username/tmp/testd/this dir/file1.txt'
removed '/home/username/tmp/testd/this dir/that dir/file2.txt'

$ find "$tmpdir/testd" -type f -printf '%T+|%p\n' | awk -F'|' '{print $2}'
    -- no output

NOTE: if the only issue causing problems is spaces in the directory (and/or file) names then this solution should be sufficient; if you need to worry about other special characters (eg, embedded linefeeds) then you'll need to expand this solution to include a custom record separator (eg, \0) and/or look at other approaches (eg, see the other answers you've received for this question)

1 Comment

thanks for all the Information and example i took this NEW: find /media/2C1F-444F/usb_musik/newMusik -type f -printf '%T+|%p\n' | sort | head -n 5 | awk -F '|' '{print $2}' | xargs -I {} sudo rm -v {} and it works fine to me
0

Your approach looks pretty fragile about special characters like spaces.

What I would do instead:

#!/bin/bash

cd "$1" || exit 1

array_list_temp=( * )
readarray -td '' array_list_temp_files < <(
    perl -l0e '
        print join "\0",
        sort { -M $b <=> -M $a }
        grep -f, @ARGV
    '  -- "${array_list_temp[@]}"
)
printf -- '%s\n' "${array_list_temp_files[@]:0:5}"

Usage:

cd /media/2C1F-444F/usb_musik/newMusik
./script.sh .

If the output looks good, you can do:

cd /media/2C1F-444F/usb_musik/newMusik
./script.sh . | xargs rm -f

2 Comments

``` :/media/2C1F-444F/usb_musik/newMusik $ test6.sh . ``` show nothing ``` :/media/2C1F-444F/usb_musik/newMusik $ ./test6.sh . -bash: ./test6.sh: No such file or directory ``` as information just below the path they are other sub, subsub and so on directorys
test6.sh need to be in the same directory and be called like ./test6.sh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.