Linux Bash Script to Find and Delete Oldest File with Special Characters and Whitespaces in a Directory Tree If Condtion Is Met

Linux bash script to find and delete oldest file with special characters and whitespaces in a directory tree if condtion is met

If you really want to process files with spaces, new lines and any special characters, you must consider using a null \0 as the limit for file names, like this:

dir=/mnt/volume0/recordings

find "$dir"/ -type f -printf '%T+ %p\0' |
sort -zk1,1 |
head -n1 -z |
cut -zd ' ' -f2- |
xargs -0 echo rm -f --

This will find files in a dir and forcefully will remove the oldest file (only one) (if the echo is removed, test it before actually using it).

Set modified date of a file to the oldest in a directory

You can loop over all files, and whenever you find one that's older than file_example, you can update file_example:

for f in ./*; do
# Skip directories
[[ -d $f ]] && continue

# Compare and update
[[ $f -ot file_example ]] && touch file_example -r "$f"
done

If you want to include hidden files, you can either loop with for f in ./* ./.*, or use shopt -s dotglob first.

This can be packaged in a shell function:

settooldest() {
local file=$1
local dir=$2
local f
for f in "$dir"/*; do
[[ -d $f ]] && continue
[[ $f -ot $file ]] && touch "$file" -r "$f"
done
}

Which is called like

settooldest file_example path/to/dir

removing all but X oldest directories on FreeBSD via Bash (no -printf, with spaces, no zsh)

... | awk 'NR>5' | while read -r timestamp filename; do rm -rf "${filename}"; done

When there are more fields than variables specified in read, the remainder is simply lumped together in the last specified variable. In our case, we extract the timestamp and use everything else as-is for the file name. We iterate the output and run an rm for each entry.

I would recommend doing a test run with echo instead of rm so you can verify the results first.


Alternately, if you'd prefer an xargs -0 version:

... | awk 'NR>5' | while read -r timestamp filename; do printf "%s\0" "${filename}"; done | xargs -0 rm -rf

This also uses the while read but prints each filename with a null byte delimiter which can be ingested by xargs -0.

Make tree command print & instead of & (And other special characters) on JSON file

Until this can be fixed and deployed everywhere:

tree . -J | recode html..utf8

But this fail with "piña colada" or "你好"

The perl alternative works with all:

tree . -J | perl -n -mHTML::Entities -e 'print HTML::Entities::decode_entities($_)'

Sample output:

[
{"type":"directory","name":".","contents":[
{"type":"file","name":"a"},
{"type":"file","name":"a&"},
{"type":"file","name":"<a>&c"},
{"type":"file","name":"b"},
{"type":"file","name":"c"},
{"type":"file","name":"d"},
{"type":"file","name":"e"},
{"type":"file","name":"f"},
{"type":"file","name":"filename.R10011.out"},
{"type":"file","name":"g"},
{"type":"file","name":"h"},
{"type":"file","name":"i"},
{"type":"file","name":"j"},
{"type":"file","name":"k"},
{"type":"file","name":"l"},
{"type":"file","name":"piña colada"},
{"type":"directory","name":"r","contents":[
]},
{"type":"file","name":"你好"}
]},
{"type":"report","directories":1,"files":17}
]

xargs and find, rm complaining about \n (newline) in filename

The ls appends a newline and the last xargs -0 says the newline is part of the file name.
Run the last xargs with -d '\n' instead of -0.

BTW, due to the way xargs works, your whole pipe is a bug waiting to happen. Consider a really long file name list produced by the find, so that the xargs -0 ls runs ls multiple times with subsets of the filenames. Only the oldest of the last ls invocation will make it past the tail -1. If the oldest file is actually, say, the very first filename output by find, you are deleting a younger file.

How to find the last field using 'cut'

You could try something like this:

echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev

Explanation

  • rev reverses "maps.google.com" to be moc.elgoog.spam
  • cut uses dot (ie '.') as the delimiter, and chooses the first field, which is moc
  • lastly, we reverse it again to get com

Check if a file exists with a wildcard in a shell script

For Bash scripts, the most direct and performant approach is:

if compgen -G "${PROJECT_DIR}/*.png" > /dev/null; then
echo "pattern exists!"
fi

This will work very speedily even in directories with millions of files and does not involve a new subshell.

Source


The simplest should be to rely on ls return value (it returns non-zero when the files do not exist):

if ls /path/to/your/files* 1> /dev/null 2>&1; then
echo "files do exist"
else
echo "files do not exist"
fi

I redirected the ls output to make it completely silent.


Here is an optimization that also relies on glob expansion, but avoids the use of ls:

for f in /path/to/your/files*; do

## Check if the glob gets expanded to existing files.
## If not, f here will be exactly the pattern above
## and the exists test will evaluate to false.
[ -e "$f" ] && echo "files do exist" || echo "files do not exist"

## This is all we needed to know, so we can break after the first iteration
break
done

This is very similar to grok12's answer, but it avoids the unnecessary iteration through the whole list.

Split linux files based on condition

You need to trim the underscore and trailing text from each line. %%_* does that:

while read -r line ; do
echo "$line" >> "${line%%_*}.txt"
done < split.txt

Explanation:

  • %: trim trailing text
  • %%: find the longest possible match
  • _*: an underscore and everything after


Related Topics



Leave a reply



Submit