How to prefix folders and files within? - linux

I'm stuck looking for a one-liner to add a prefix to all subfolder names and file names in a directory
eg "AAA" in the examples below
/folder/AAAfile.txt
/folder/AAAread/AAAdoc.txt
/folder/AAAread/AAAfinished/AAAread.txt
I've tried using xargs and find, but can't get them to go recursively through the subdirectories and their contents. Any suggestions?
James

You could use something like that
find . -mindepth 1 | sort -r | xargs -l -I {} bash -c 'mv $1 ${1%/*}/AAA${1##*/}' _ {}
Tested with your folder structure, executed from the root (same as AAAfile.txt).

The following script should meet your need (ran it from inside your folder directory):
for i in `ls -R`;do
dname=`dirname $i`
fname=AAA`basename $i`
if [ -f $i ]
then
mv $i $dname/$fname
fi
#this could be merged with previous condition but have been kept just to avoid invalid directory warning
if [ -d $i ]
then
mv $i $dname/$fname
fi
done

Related

How do I tweak my bash script below for searching sub directories

I have a directory with files in the following strcuture:
HomeTransaction1/Date1/transactionfile1.txt
HomeTransaction1/Date1/transactionfile1.xls
HomeTransaction1/Date1/transactionfile2.xls
HomeTransaction1/Date1/transactionfile2.txt
HomeTransaction1/Date1/transactionfile3.txt
HomeTransaction1/Date2/transactionfile1.txt
HomeTransaction1/Date3/transactionfile2.txt
HomeTransaction1/Date3/transactionfile3.txt
HomeTransaction2/Date1/transactionfile1.txt
HomeTransaction2/Date1/transactionfile2.txt
HomeTransaction3/Date1/transactionfile3.txt
I'm trying to get for a specific thing in the transaction files that end in .txt so I'm trying to come up with a bash script to achieve this. Conceptually, this is my thought process.
A - List each folder in the current directory. I this example, it'll be HomeTransaction1, HomeTransaction2 and HomeTransaction3
B - for each folder in B list all the folders(the Date folders)
C - for each folder in step B, run "grep " for files with .txt extension
This is what I have come up with so far:
#!/bin/bash
for FILE in `ls -l`
do
if test -d $FILE && (startswith "HomeTrasaction") //I want to add a condition to check that the directory name and starts with "HomeTrasaction"
then
cd $FILE // example cd to 'HomeTransaction1' directory
echo "In HomeTransaction directory $FILE"
for SUB_FILE in `ls -l`
do
cd $SUB_FILE //example cd to 'Date1'
echo "In Date directory $FILE"
for TS_FILES in ($find . -print | grep .txt)
grep "text-to-search" $SUB_FILE
fi
done
I appreciate any help in finalizing my script. Thank you.
The solution is actually pretty simple
find ./HomeTrasaction* -iname "*.txt" -exec grep -i "phrase" {} \;
find ./HomeTrasaction* - search each directory that start with this phrase, in the current directory.
-iname "*.txt" - for each file that ends with .txt
-exec grep -i "phrase" {} ; - grep for the word "phrase"
If this is still not clear "man find" :)

Bash script creates symlink inside directory aswell

I have a bash script:
for file in `find -mindepth 1 -maxdepth 1`
do
old=`pwd`
new=".${file##*/}"
newfile="$old/${file##*/}"
cd
wd=`pwd`
link="$wd/$new"
ln -s -f $newfile $link
cd $old
done
This is meant to create a symlink in the user's home directory with '.' prepended to all the files and directories in the current working directory. This works fine, however, it also creates a symlink inside any sub directories to the same directory. E.G. foo will now have a link at ~/.foo and foo/foo.
Is there any way I can fix this?
EDIT: Thanks to Sameer Naik and dave_thompson_085 I have changed it up a bit, but the problem still persists even when a alternate directory is given as an argument. It isn't a problem with sub directories it is that two links are being made, one to ~/.foo123 and one to foo123/foo123 not a link is being made to ~/ for foo1 and foo1/foo2.
for file in `ls -l | grep -v total | awk '{print $NF;}'`
do
old=`pwd`
wd=`cd $1 && pwd`
new=".${file}"
newfile="$wd/${file}"
cd
wd=`pwd`
link="$wd/$new"
ln -s -f $newfile $link
cd $old
done
Since you don't want recurse into sub-directories, try using
for file in `ls -l | grep -v ^d | awk '{print $NF;}'`
or use -type f in find to exclude subdirectories

using IF to see a directory exists if not do something

I am trying to move the directories from $DIR1 to $DIR2 if $DIR2 does not have the same directory name
if [[ ! $(ls -d /$DIR2/* | grep test) ]] is what I currently have.
then
mv $DIR1/test* /$DIR2
fi
first it gives
ls: cannot access //data/lims/PROCESSING/*: No such file or directory
when $DIR2 is empty
however, it still works.
secondly
when i run the shell script twice.
it doesn't let me move the directories with the similar name.
for example
in $DIR1 i have test-1 test-2 test-3
when it runs for the first time all three directories moves to $DIR2
after that i do mkdir test-4 at $DIR1 and run the script again..
it does not let me move the test-4 because my loop thinks that test-4 is already there since I am grabbing all test
how can I go around and move test-4 ?
Firstly, you can check whether or not a directory exists using bash's built in 'True if directory exists' expression:
test="/some/path/maybe"
if [ -d "$test" ]; then
echo "$test is a directory"
fi
However, you want to test if something is not a directory. You've shown in your code that you already know how to negate the expression:
test="/some/path/maybe"
if [ ! -d "$test" ]; then
echo "$test is NOT a directory"
fi
You also seem to be using ls to get a list of files. Perhaps you want to loop over them and do something if the files are not a directory?
dir="/some/path/maybe"
for test in $(ls $dir);
do
if [ ! -d $test ]; then
echo "$test is NOT a directory."
fi
done
A good place to look for bash stuff like this is Machtelt Garrels' guide. His page on the various expressions you can use in if statements helped me a lot.
Moving directories from a source to a destination if they don't already exist in the destination:
For the sake of readability I'm going to refer to your DIR1 and DIR2 as src and dest. First, let's declare them:
src="/place/dir1/"
dest="/place/dir2/"
Note the trailing slashes. We'll append the names of folders to these paths so the trailing slashes make that simpler. You also seem to be limiting the directories you want to move by whether or not they have the word test in their name:
filter="test"
So, let's first loop through the directories in source that pass the filter; if they don't exist in dest let's move them there:
for dir in $(ls -d $src | grep $filter); do
if [ ! -d "$dest$dir" ]; then
mv "$src$dir" "$dest"
fi
done
I hope that solves your issue. But be warned, #gniourf_gniourf posted a link in the comments that should be heeded!
If you need to mv some directories to another according to some pattern, than you can use find:
find . -type d -name "test*" -exec mv -t /tmp/target {} +
Details:
-type d - will search only for directories
-name "" - set search pattern
-exec - do something with find results
-t, --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY
There are many examples of exec or xargs usage.
And if you do not want to overwrite files, than add -n option to mv command:
find . -type d -name "test*" -exec mv -n -t /tmp/target {} +
-n, --no-clobber do not overwrite an existing file

A bash script to run a program for directories that do not have a certain file

I need a Bash Script to Execute a program for all directories that do not have a specific file and create the output file on the same directory.This program needs an input file which exist in every directory with the name *.DNA.fasta.Suppose I have the following directories that may contain sub directories also
dir1/a.protein.fasta
dir2/b.protein.fasta
dir3/anyfile
dir4/x.orf.fasta
I have started by finding the directories that don't have that specific file whic name is *.protein.fasta
in this case I want the dir3 and dir4 to be listed (since they do not contain *.protein.fasta)
I have tried this code:
find . -maxdepth 1 -type d \! -exec test -e '{}/*protein.fasta' \; -print
but it seems I missed some thing it does not work.
also I do not know how to proceed for the whole story.
This is a tricky one.
I can't think of a good solution. But here's a solution, nevertheless. Note that this is guaranteed not to work if your directory or file names contain newlines, and it's not guaranteed to work if they contain other special characters. (I've only tested with the samples in your question.)
Also, I haven't included a -maxdepth because you said you need to search subdirectories too.
#!/bin/bash
# Create an associative array
declare -A excludes
# Build an associative array of directories containing the file
while read line; do
excludes[$(dirname "$line")]=1
echo "excluded: $(dirname "$line")" >&2
done <<EOT
$(find . -name "*protein.fasta" -print)
EOT
# Walk through all directories, print only those not in array
find . -type d \
| while read line ; do
if [[ ! ${excludes[$line]} ]]; then
echo "$line"
fi
done
For me, this returns:
.
./dir3
./dir4
All of which are directories that do not contain a file matching *.protein.fasta. Of course, you can replace the last echo "$line" with whatever you need to do with these directories.
Alternately:
If what you're really looking for is just the list of top-level directories that do not contain the matching file in any subdirectory, the following bash one-liner may be sufficient:
for i in *; do test -d "$i" && ( find "$i" -name '*protein.fasta' | grep -q . || echo "$i" ); done
#!/bin/bash
for dir in *; do
test -d "$dir" && ( find "$dir" -name '*protein.fasta' | grep -q . || Programfoo"$dir/$dir.DNA.fasta");
done

Shell Script for renaming and relocating the files

I am working on something and need to solve the following. I am giving a analogous version of mine problem.
Say we have a music directory, in which there are 200 directories corresponding to different movies. In each movie directory there are some music files.
Now, say a file music.mp3 is in folder movie.mp3 . I want to make a shell script such that it renames the file to movie_music.mp3 and put it in some folder that I mention to it. Basically, all the files in the subdirectories are to be renamed and to be put in a new directory.
Any workaround for this?
This script receives two arguments: the source folder and the destination folder. It will move every file under any directory under the source directory to the new directory with the new filename:
#!/bin.sh
echo "Moving from $1 to $2"
for dir in "$1"/*; do
if [ -d "$dir" ]; then
for file in "$dir"/*; do
if [ -f "$file" ]; then
echo "${file} -> $2/`basename "$dir"`_`basename "${file}"`"
mv "${file}" "$2"/`basename "$dir"`_`basename "${file}"`
fi
done
fi
done
Here is a sample:
bash move.sh dir dir2
Moving from dir to dir2
dir/d1/f1 -> dir2/d1_f1
dir/d1/f2 -> dir2/d1_f2
dir/d2/f1 -> dir2/d2_f1
dir/d2/f2 -> dir2/d2_f2
Bash:
newdir=path/to/new_directory;
find . -type d |while read d; do
find "$d" -type f -maxdepth 1 |while read f; do
movie="$(basename "$d" |sed 's/\(\..*\)\?//')"
mv "$f" "$newdir/$movie_$(basename $f)";
done;
done
Assuming the following directory tree:
./movie1:
movie1.mp3
./movie2:
movie2.mp3
The following one-liner will create 'mv' commands you can use:
find ./ | grep "movie.*/" | awk '{print "mv "$1" "$1}' | sed 's/\(.*\)\//\1_/'
EDIT:
If your directory structure contains only the relevant directories, you can expand use the following grep instead:
grep "\/.*\/.*"
Notice it looks file anything with at least one directory and one file. If you have multiple inner directories, it won't be good enough.

Resources