Suppose a particular command generates few files (I dont know the name of these files). I want to move those files into a new folder. How to do it in shell script?
i can't use :
#!/bin/bash
mkdir newfolder
command
mv * newfolder
as the cwd contains lot of other files as well.
The first question is can you just run command with newfolder as the current directory to generate the files in the right place it begin with:
mkdir newfolder
cd newfolder
command
Or if command is not in the path:
mkdir newfolder
cd newfolder
../command
If you can't do this then you'll need to capture lists of before and after files and compare. An inelegant way of doing this would be as follows:
# Make sure before.txt is in the before list so it isn't in the list of new files
touch before.txt
# Capture the files before the command
ls -1 > before.txt
# Run the command
command
# Capture the list of files after
ls -1 > after.txt
# Use diff to compare the lists, only printing new entries
NEWFILES=`diff --old-line-format="" --unchanged-line-format="" --new-line-format="%l " before.txt after.txt`
# Remove our temporary files
rm before.txt after.txt
# Move the files to the new folder
mkdir newfolder
mv $NEWFILES newfolder
use pattern matching:
$ ls *.jpg # List all JPEG files
$ ls ?.jpg # List JPEG files with 1 char names (eg a.jpg, 1.jpg)
$ rm [A-Z]*.jpg # Remove JPEG files that start with a capital letter
Example shamelessly taken from here where you can find some more useful information about it.
If you'd like to move them into a sub-folder:
mv `find . -type f -maxdepth 1` newfolder
Setting a -maxdepth 1 will only find the files in the current directory and will not recurse. Passing in -type f means "find all files" ("d" would, respectively, mean "find all directories").
Assuming that your command prints out names with one per line, this script will work.
my_command | xargs -I {} mv -t "$dest_dir" {}
Related
I have directory structure like this.
From this I want to create different zip files such as
data-A-A_1-A_11.zip
data-A-A_1-A_12.zip
data-B-B_1-B_11.zip
data-C-C_1-C_11.zip
while read line;
do
echo "zip -r ${line//\//-}.zip $line";
# zip -r "${line//\//-}.zip" "$line"
done <<< "$(find data -maxdepth 3 -mindepth 2 -type d)"
Redirect the result of a find command into a while loop. The find command searches the directory data for directories only, searching 3 directories deep only. In the while loop with use bash expansion to convert all forward slashes to "-" and add ".zip" in such a way that we can build a zip command on each directory. Once you are happy that the zip command looks fine when echoed for each directory, comment in the actual zip command
As a rather novice Linux user, I can't seem to find how to do this.
I am trying to move unique files all in one directory into another directory.
Example:
$ ls
vehicle car.txt bicycle.txt airplane.html train.docx (more files)
I want car.txt, bicycle.txt, airplane.html, and train.docx inside vehicle.
Right now I do this by moving the files individually:
$ mv car.txt vehicle
$ mv bicycle.txt vehicle
...
How can I do this in one line?
You can do
mv car.txt bicycle.txt vehicle/
(Note that the / above is unnecessary, I include it merely to ensure that vehicle is a directory.)
You can test this as follows:
cd #Move to home directory
mkdir temp #Make a temporary directory
touch a b c d #Make test (empty) files ('touch' also updates the modification date of an existing file to the current time)
ls #Verify everything is there
mv a b c d temp/ #Move files into temp
ls #See? They are gone.
ls temp/ #Oh, there they are!
rm -rf temp/ #DESTROY (Be very, very careful with this command)
Shorthand command to move all .txt file
You can try using a wildcard. In the code below, * will match all the files which have any name ending with .txt or .docx, and move them to the vehicle folder.
mv *.txt *.docx vehicle/
If you want to move specific files to a directory
mv car.txt bicycle.txt vehicle/
Edit: As mentioned in a comment, If you are moving files by hand, I suggest using mv -i ... which will warn you in case the destination file already exists, giving you a choice of not overwriting it. Other 'file destroyer' commands like cp & rm too have a -i option
mv command in linux allow us to move more than one file into another directory. All you have to do is write the name of each file you want to move, seperated by a space.
Following command will help you:
mv car.txt bicycle.txt airplane.html train.docx vehicle
or
mv car.txt bicycle.txt airplane.html train.docx vehicle/
both of them will work.
You can move multiple files to a specific directory by using mv command.
In your scenario it can be done by,
mv car.txt bicycle.txt airplane.html train.docx vehicle/
The point you must note is that the last entry is the destination and rest everything except mv is source.
One another scenario is that the destination is not present in our directory,then we must opt for absolute path in place of vehicles/.
Note: Absolute path always starts from / ,which means we are traversing from root directory.
I have written a small bash script that will move multiple files(matched using pattern) present in multiple directories(matched using pattern) to a single location using mv and find command in bash
#!/bin/bash
for i in $(find /path/info/*/*.fna -type f) # find files and return their path
do
mv -iv $i -t ~/path/to/destination/directory # move files
done
$() is for command substitution(in other words it expand the expression inside it)
/*/ wild card for matching any directory, you can replace this with any wild card expression
*.fna is for finding any file with.fna extension
-type f is for getting the full path info of the located file
-i in mv is for prompt before overwrite( extra caution in case the wild card exp was wrong)
-v for verbose
-t for destination
NOTE: the above flags are not mandatory
Hope this helps
I'm trying write a script in linux. Where I have some csv files in Two different folders(A and B) and then after some processing copy of rejected files are moving to Bad Folder.
SO I want bad files to be deleted from Table A and B which have copied to Bad Folder.
Can you help me to write this script for linux?
Best
lets say name of Bad Folder is 'badFolder' and considering 'A', 'B' and 'badFolder' are in same directory
Steps to delete files from folder A and B:
step 1: change current directory to your 'badFolder'
cd badFolder
step 2: delete identical files
find . -type f -exec rm -f ../A/{} \;
find . -type f -exec rm -f ../B/{} \;
The argument -type f tells to look for files, not directories.
The -exec ... \; argument tells that, once it finds a file in 'badFolder', it should run the command rm -f on its counterpart in the A subdirectory.
Because rm is given with the -f option, it will silently ignore files that don't exist.
Also, it will not prompt before deleting files. This is very handy when deleting a large number of files. However, be sure that you really want to delete the files before running this script.
#!/bin/bash
#Set the working folder in which you want to delete the file
Working_folder=/<Folder>/<path>
cd $Working_folder
#command to delete all files present in folders
rm <filenames seperated by space>
echo "files are deleted"
#if you want to delete all files you can use wild card character
# e.g. command rm *.*
# if you want to delete a particular file say for deleting .csv file you can use command rm *.csv command
Set variables containing the paths of your A, B and BAD directories.
Then you can do something along the lines of
for file in ls ${PATH_TO_BAD}
do
rm ${PATH_TO_A}/$file
rm ${PATH_TO_B}/$file
done
This is iterating over the BAD directory and any file it finds, it deletes from the A and B directories.
I have a parent/ folder with a couple of subfolders in it. Structure:
/parent/
/subfolder_1/
- file_1.txt
- file_2.txt
/subfolder_2/
- file_3.txt
- file_4.txt
Now, I need to recursively move the contents of parent/ folder to the empty parent_tmp/ directory. Thing is, I need to keep the original folder structure in parent/.
Expected outcome after moving:
/parent/
/subfolder_1/
(empty)
/subfolder_2/
(empty)
/parent_tmp/
/subfolder_1/
- file_1.txt
- file_2.txt
/subfolder_2/
- file_3.txt
- file_4.txt
Normally, I would simply do
mv parent/* parent_tmp
but this will, of course, move the subfolders permanently.
Is there a way to adjust the mv command to keep the original structure of the source directory?
Note:
I realize that I can e.g. copy parent/ to parent_tmp, and then remove the files in parent/ subfolders. This is plan B to me.
You can use find from parent of parent and parent_tmp directoroies:
find parent -type f -exec bash -c 'mkdir -p "parent_tmp/${1%/*}" &&
mv "$1" "parent_tmp/${1%/*}"' - {} \;
You could copy the files
cp -r parent/* parent_tmp/
or create hard links (should be a lot faster for big files)
cp -l -r parent/* parent_tmp/
and then delete the original files
find parent -type f -delete
while keeping the directory structure.
Zip the content of the parent folder and Unzip it in the target folder.
Quick and Dirty:
I don't think you'll find a tool or option in the mv command to do what you want, but you should be able to achieve the desired goal by using find:
cd parent && while read file ; do dirname="$(dirname "$file")" ; mkdir -p ../parent_tmp/"$dirname"/; mv "$file" "../parent_tmp/"${file#}"" ; done < <( find . -type f ) && cd -
Function
If you use this a lot then you can add the above to your ~/.basrc like so (append to the end of the file):
alias mvkp=moveandkeep
moveandkeep() {
cd "$1"
while read file ;
do dirname="$(dirname "$file")" ;
mkdir -p "$2"/"${dirname#}";
mv "$file" ""$2"/"${file#}"";
done < <(find . -type f)
cd -
}
Now you could simply do the following: (Full path to directories required)
mvkp /home/user/parent /home/user/parent_tmp
I have something like this:
v_1/file.txt
v_2/file.txt
v_3/file.txt
...
and I want to rename those files to something like this:
v_1.txt
v_2.txt
v_3.txt
...
in the same directory.
I guess I can use rename but I can't figure out how to use it with folder and file renaming at the same time.
The result can be achieved with a bash for loop and mv:
for subdir in *; do mv $subdir/file.txt $subdir.txt; done;
Note that the solution above will not work if the directory name contains spaces. Related link.
Another solution based on comments (that works for directories having spaces in the name as well):
find . -type d -not -empty -exec echo mv \{\}/file.txt \{\}.txt \;
You can use rnm. The command would be:
rnm -fo -dp -1 -ns '/pd0/.txt' -ss '\.txt$' /path/to/the/directory
-fo implies file only mode.
-dp directory depth. -1 makes it recursive to all subdirectories.
-ns implies name string i.e the new name of the file.
/pd0/ is the immediate parent directory of the file which is subject to rename operation.
-ss is a search string (regex). '\.txt$' regex searches for file with .txt at the end of the filename.
/path/to/the/directory this is the path where the v_1, v_2 ... directories reside. You can pass the directories ( v_1, v_2 ...) too in place of the parent directory path. For example:
#from inside the parent directory
rnm -fo -dp -1 -ns '/pd0/.txt' -ss '\.txt$' v_*
Seem pretty straightforward to me:
$ mkdir /tmp/sandbox
$ cd /tmp/sandbox
$ mkdir v_{1,2,3}
$ touch v_{1,2,3}/file.txt
$ rename -v 's#/file##' v_{1,2,3}/file.txt
rename v_1/file.txt v_1.txt
rename v_2/file.txt v_2.txt
rename v_3/file.txt v_3.txt
$ ls -F
v_1/ v_1.txt v_2/ v_2.txt v_3/ v_3.txt