move downloaded files to particular directories - inotify for dummies? - shell

I wonder whether nobody else wants to move files downloaded from the web to file-specific directories? - Bank account statements go to various "Bank account statements" folders, depending which account it is, invoices go to their specific folders etc.
Assumed they all have their characteristic file name beginning, it should not be so difficult to get that automatized. There is a firefox plugin for that, but I could never make it work. So my idea was to use inotify for the download folder (or another suitable tool). But I never found really dummy-proof instuctions how to obtain that.
Would someone be so kind and provide all the steps to set up such a service?
Thanks a lot in advance,
Wolf

After quite some trial and error, I came to a working solution. This script sorts downloaded files with certain patterns to the defined target directories:
#!/bin/bash
cd <my-download-directory>
inotifywait -mq -e moved_to --format %f <my-download-directory> | while read FILE
echo "name of new file: "$FILE
do
if [[ $FILE =~ regex-search-pattern1 ]]; then mv $FILE <target-directory1> ; fi
if [[ $FILE =~ regex-search-pattern2 ]]; then mv $FILE <target-directory2> ; fi
if [[ $FILE =~ regex-search-pattern3 ]]; then mv $FILE <target-directory3>; fi
... more if desired
done
In general such a feature is quite useful - I'd really like to have a GUI for it.
Cheers,
Wolf

Related

searching file existence at any depth in bash

I need to check if a file exists in directory using bash. I have tried below method but it needs complete path as input.
if [ -e /*/my_file.txt ] ;
then
echo "file found"
else
echo "not found"
fi
Is there any way that I can check if the file exists at any depth dynamically.
NOTE: I don't want to use "find" as it takes lot of time to execute.
If you are using bash 4, you can write patterns that recursively descend a hierarchy:
shopt -s globstar
for f in /**/myfile.txt; do
if [[ -e $f ]]; then
found=1
echo "File found"
break
fi
done
if [[ $found -ne 1 ]]; then
echo "File not found"
fi
Using find:
found=$( find / -name myfile.txt )
if [[ -n $found ]]; then
echo "File found"
else
echo "File not found"
fi
If really speed is your concern, file globbing like ls * */* */*/* is not helping you that much. And it has its limit with this error: Argument list too long. find is a useful tool for finding stuff. It is very flexible. But like using file globbing, it has to scan the directory tree with every invocation. For occasional searches, like for maintenance, this is totally acceptable. But if this is part processing pipeline, the speed is not acceptable. You need an optimised database for that.
The simplistic way
Most every UNIX I know is shipped with locate.
If it is preinstall you can search like this:
$ locate -b '\my_file.txt'
The backslash in front of my_file.txt is intended. It switches off wildcard search. Adding -i gives case insensitive search.
If the command is not available it should be installable from your OS repository. For Debian/Ubuntu: apt install locate. For first init run /etc/cron.daily/locate as root or with sudo.
The database is updated on a daily basis. For some applications, this interval is probably too long. By moving the cronjob from daily to like every 3 hours, you get more recent results.
The realtime way ...
This is a bit out of the scope of this answer. But you would need some kind of deamon, that would watch kernel inotify events for directory changes. These in turn would be reflected in a database, that can be queried through some API. Like Spotlight from MacOS or Tracker from Gnome.
find is the proper solution.
however you can use bash expansion feature
if ls */* | grep -q my_file.txt
then echo file found
else echo file not found
fi
note
that above solution will not find my_file.txt if a top level.
if my_file.txt is part of a directory name you might get a wrong result.
if there are many (thousands) directories and many files / expansion might get paste bash limit (arg list too long)
you can ls * */* */*/* | grep with limit state above.

Simple BASH script needed: moving and renaming files

Decades ago I was a programmer (IBM assembly, Fortran, COBOL, MS DOS scripting, a bit of Visual Basic.) Thus I'm familiar with the generalities of IF-Then-Else, For loops, etc.
However, I'm now needing to delve into Bash for my current job, and I'm having a difficult time with syntax and appropriate commands for what I need.
I'm in need of a trivial (concept-wise) script, which will:
Determine if a specific folder (e.g., ~/Desktop/Archive Folder) exists on the user Desktop
If not, create it ("Archive")
Move all files/folders on desktop - except for ~/Desktop/Archive, into "Archive Folder" - AND appending a timestamp onto the end of the filenames being moved.
It is this very last piece - the timestamp addition - which is holding me up.
I'm hoping a clear and simple solution can be sent my way. Here is what I've come up with so far:
#!/bin/bash
shopt -s extglob
FOLDERARCH="Archive Folder"
cd ~/Desktop
if [ ! -d $"FOLDERARCH" ]; then
mkdir "$FOLDERARCH"
echo "$FOLDERARCH did not exist, was created"
fi
mv !(-d "$FOLDERARCH") "$FOLDERARCH"
One final note: the script above works (without the timestamp piece) yet also ends with the message
mv: rename Archive Folder to Folder/Archive Folder: Invalid argument
Why?
Any help will be deeply, deeply appreciated. Please assume I know essentially zilch about the BASH environment, cmds and their arguments - this first request for assistance marks my first step into the journey of becoming at least proficient.
Update
First: much gratitude for the replies I've gotten; they've been very useful.
I've now got was it essentially a working version, but with some oddities I do not understand and, after hours of attempted research, have yet to understand/solve.
I'm hoping for some insight; I feel I'm on the verge of making some real headway in comprehending, but these anomalies are hindering my progress. Here's my (working, with "issues") code so far:
shopt -s extglob
FOLDERARCH="Archives"
NEWARCH=$(date +%F_%T)
cd ~/Desktop
if [ ! -d $"FOLDERARCH" ]; then
mkdir "$FOLDERARCH"
echo "$FOLDERARCH did not exist, was created"
fi
mkdir "$FOLDERARCH/$NEWARCH"
mv !(-d "$FOLDERARCH") $FOLDERARCH/$NEWARCH
This in fact largely accomplishes my goal, but:
In the case where the desktop Archives folder already exists, I'm expecting the if-then construct to simply follow through (with no echo msg) to the following mkdir command, but instead the msg "Archives not exist, was created" msg is output anyway (erroneously). Any answers as to why?
The script completes with the following msg:
mv: rename Archives to Archives/2016-01-10_00:06:54/Archives: Invalid argument
I don't understand this at all; what should be happening is that all files/folders on the desktop EXCEPT the /Desktop/Archives folder should be moved into a newly created "subfolder" of /Desktop/Archives, e.g., /Desktop/Archives/2016-01-10_00:06:54. In fact, the move accomplishes my goal, but that the message arises makes no sense to me. What is the invalid argument?
One last note: at this point in my newbie-status I'm looking for code which is clear and easy to read, versus much more elegant/sophisticated one-line piped-command solutions. I look forward to working my way up to those in due time.
You have several options. One of the simplest is to loop over the directories below ~/Desktop and if they are not "$FOLDERARCH", move them to "$FOLDERARCH", e.g.:
for i in */; do
[ "$i" != "$FOLDERARCH"/ ] && mv "$i" "$FOLDERARCH"
done
I haven't run a test case, but something similar to the following should work.
#!/bin/bash
shopt -s extglob
FOLDERARCH="Archive Folder"
cd ~/Desktop || { printf "failed to change to '~/Destop'\n"; exit 1; }
if [ ! -d "$FOLDERARCH" ]; then
if mkdir "$FOLDERARCH" , then
echo "$FOLDERARCH did not exist, was created"
else
echo "error: failed to create '$FOLDERARCH'"
exit 1
fi
fi
for i in */; do
[ "$i" != "$FOLDERARCH"/ ] && mv "$i" "$FOLDERARCH"
done
I apologize, I forgot the datestamp portion. As pointed out in the comments, you can include the datestamp (set the format to your taste) with something similar to the following:
tstamp=$(date +%s)
for i in */; do
[ "$i" != "$FOLDERARCH"/ ] && mv "$i" "$FOLDERARCH/${i}_${tstamp}"
done

Bash If then that reads a list in a file condition

Here is the condition:
I have a file with all packages installed.
I have a folder with all kinds of other packages, but they include all of the ones in the list, plus more.
I need a bash script that will read the file and check a folder for packages that don't exist in the list then remove them, they are not needed, but keep the packages that are on the list in that folder.
Or perhaps the bash should read folder then if packages in the folder aren't on the list them rm -f that or those packages.
I am familiar with writing if then conditional statements, I just don't know how to do if making the items in the list a variable or variables (in a loop).
thanks!
I would move the packages on the list to a new folder, delete the original folder, and move the temporary folder back:
DIR=directory-name
mkdir "$DIR-tmp"
while read pkgname; do
if [[ -f "$DIR/$pkgname" ]]; then
mv "$DIR/$pkgname" "$DIR-tmp"
fi
done < package-list.txt
# Confirm $DIR-tmp has the files you want first!
rm -rf "$DIR"
mv "$DIR-tmp" "$DIR"
I think you want something like this:
for file in $(ls folder) ; do
grep -E "$file" install-list-file >/dev/null || \
echo $file
done > rm-list
vi rm-list # view file to ensure correct
rm $(<rm_list)
There are ways to make this faster (using parameter substitution to avoid fork/exec's), but I recommend avoiding fancy shell stuff [${file##*/}] until you've got the basics down. Also, this script basically translates the description into a script and is not intended to be much more than a guide on how to approach the problem.

Script to rename, move and compress images automagically

I'm trying to create a script on my Raspberry's Xbian that will "watch" a folder and compress any folders with images I saved there from Google Image Search.
What I want: The script will move all folders with " - Google Search" in their name to a temp folder, rename them removing the " - Google Search" part, leaving only the subject of the search query. Then, it will sequentially number the files in each folder using the folder name / the search query as their new name. So, "Random file.jpg" and "anoth3r_rand0m_file.png" will become "search_topic_01.jpg" and "search_topic_02.jpg".
Then, they'll be all moved to another folder, an "Incoming Images" one, where ImageMagick will do its magic on them, at the same time moving them to a "Ready Images" folder.
Still with me?
Here's what I got so far, from bundling stuff I found online together with my limited knowledge of Bash scripting:
echo "making temp"
mkdir /media/dBox/downloads/Xyma/temp
wait
echo "moving files"
mv /media/dBox/downloads/Xyma/*Google\ Search /media/dBox/downloads/Xyma/temp
wait
echo "renaming folders"
rename s/\ -\ Google\ Search// /media/dBox/downloads/Xyma/temp/*
wait
echo "renaming files"
for dir in /media/dBox/downloads/Xyma/temp/; do
if test -d "$dir"; then
(
cd $dir
for file in *; do
newfile=$dir.${file#*.}
mv "$file" "$newfile"
done
)
fi
done
wait
echo "making ready subfolder"
mkdir /media/dBox/downloads/Xyma/temp/00_Unreg_Ready_Image_Folders
wait
echo "moving folders to ready folder"
mv /media/dBox/downloads/Xyma/temp/* /media/dBox/downloads/Xyma/00_Unreg_Ready_$
wait
echo "removing temp folder"
rmdir /media/dBox/downloads/Xyma/temp
...and let's just say "AAARGHRGHRGHHhh".
I'm sure that there must be an even simpler way, with, say, a five-word command and maybe two parameters, that will auto magically do everything and sprinkle it with stardust, or generally "a simpler and better way to do it", but it's currently slipping my mind.
So, I'm open to ideas and suggestions.
Any help? Anyone?
Help!

A simple mv command in a BASH script

The aim of my script:
look at all the files in a directory ($Home/Music/TEST) and its sub-directories (they are music files)
find out what music genre each file belongs to
if the genre is Heavy, then move the file to another directory ($Home/Music/Output)
This is what I have:
#!/bin/bash
cd Music/TEST
for files in *
do
if [ -f "$files" ];then
# use mminfo to get the track info
genre=`mminfo "$files"|grep genre|awk -F: '{print $2}'|sed 's/^ *//g'|sed 's/[^a-zA-Z0-9\ \-\_]//g'`
if [ $genre = Heavy ] ;then
mv "$files" "~/Music/Output/$files"
fi
fi
done
Please tell me how to write the mv command. Everything I have tried has failed. I get errors like this:
mv: cannot move ‘3rd Eye Landslide.mp3’ to ‘/Music/Output/3rd Eye Landslide.mp3’: No such file or directory
Please don't think I wrote that mminfo line - that's just copied from good old Google search. It's way beyond me.
Your second argument to mv appears to be "~/Music/Output/$files"
If the ~ is meant to signify your home directory, you should use $HOME instead, like:
mv "$files" "$HOME/Music/Output/$files"
~ does not expand to $HOME when quoted.
By the look of it the problem occurs when you move the file to its destination.Please check that /Music/Output/ exits from your current directory.Alternatively use the absolute path to make it safe. Also it's a good idea not use space in the file-name.Hope this will helps.:)
Put this command before mv command should fix your problem.
mkdir -p ~/Music/Output

Resources