Linux command error for renaming multiple files in folder - linux

I am using this command and sample_numbers_names.csv file to rename multiple files in the folder which has subfolders with different file names.
while IFS=, read -a p ; do SAMPLENUM=${p[0]} ; find . -type f -name "${SAMPLENUM}*" -exec rename -v "${SAMPLENUM}" "${p[1]}_${SAMPLENUM}" {} \; ; done < sample_numbers_names.csv
The csv file has two columns first for old name and next for the new name. for e.g.
111,abc
222,xyz
After using this command the out put I am getting is like this
111.txt is converted to abc._111.txt
How to remove that dot after abc so that renamed file will look like abc_111.txt rather than abc._111.txt

The following seems to work as desired:
$ cat sample_numbers_names.csv
111,abc
222,xyz
$ mkdir -p foo/bar
$ touch foo/bar/{111,222}.txt
$ while IFS=, read old new ; do find . -type f | xargs rename "s/${old}/${new}_${old}/"; done < sample_numbers_names.csv
$ ls foo/bar/
abc_111.txt xyz_222.txt

Related

How to rename multiple files with the same name when moving them from all subdirectories into one new location

I wanted to group some log files from multiple subdirectories into one new.
The problem is with moving multiple files with exact same names from multiple location into one.
I wanted to use something as below, but I need to add something to change the names of the files when copying.
find . -name "raml-proxy.log" -exec mv {} raml_log_files/ \;
A bit of find and awk could produce the list of mv commands you need. Let's first assume that your log files have quiet names without newline characters:
find . -type f -name "raml-proxy.log" |
awk -v dir="raml_log_files" '{s=$0; sub(/.*\//,""); n[$0]++;
printf("mv \"%s\" \"%s/%s.%d\"\n", s, dir, $0, n[$0])}' > rename.sh
And then, after careful inspection of file rename.sh, just execute it. Explanation: sub(/.*\//,"") removes the directory part, if any, from the current record, including the last / character. n is an associative array where the keys are the log file names and the values are a counter that increments each time a log file with that name is encountered. Demo:
$ mkdir -p a b c d
$ touch a/a b/a c/a d/b
$ find . -type f | awk -v dir="raml_log_files" '{s=$0; sub(/.*\//,""); n[$0]++;
printf("mv \"%s\" \"%s/%s.%d\"\n", s, dir, $0, n[$0])}'
mv "./b/a" "raml_log_files/a.1"
mv "./a/a" "raml_log_files/a.2"
mv "./d/b" "raml_log_files/b.1"
mv "./c/a" "raml_log_files/a.3"
If there can be newline characters in the names of your log files we can use the NUL character as record separator, instead of the newline:
find . -type f -name "raml-proxy.log" -print0 |
awk -v dir="raml_log_files" -v RS=$'\\0' '{s=$0; sub(/.*\//,""); n[$0]++;
printf("mv \"%s\" \"%s/%s.%d\"\n", s, dir, $0, n[$0])}' > rename.sh

Find Files Containing Certain String and Copy To Directory Using Linux

I am trying to find files that contain a certain string in a current directory and make a copy of all of these files into a new directory.
My scrip that I'm trying to use
grep *Qtr_1_results*; cp /data/jobs/file/obj1
I am unable to copy and the output message is:
Usage: cp [-fhipHILPU][-d|-e] [-r|-R] [-E{force|ignore|warn}] [--] src target
or: cp [-fhipHILPU] [-d|-e] [-r|-R] [-E{force|ignore|warn}] [--] src1 ... srcN directory
Edit: After clearing things up (see comment)...
cp *Qtr_1_results* /data/jobs/file/obj1
What you're doing is just greping for nothing. With ; you end the command and cp prints the error message because you only provide the source, not the destination.
What you want to do is the following. First you want to grep for the filename, not the string (which you didn't provide).
grep -l the_string_you_are_looking_for *Qtr_1_results*
The -l option gives you the filename, instead of the line where the_string_you_are_looking_for is found. In this case grep will search in all files where the filename contains Qtr_1_results.
Then you want send the output of grep to a while loop to process it. You do this with a pipe (|). The semicolon ; just ends lines.
grep -l the_string_you_are_looking_for *Qtr_1_results* | while read -r filename; do cp $filename /path/to/your/destination/folder; done
In the while loop read -r will put the output of grep into the variable filename. When you assing a value to a variable you just write the name of the variable. When you want to have the value of the variable, you put a $ in front of it.
You can use multiple exec in find to do this task
For eg:
find . -type f -exec grep -lr "Qtr_1_results" {} \; -exec cp -r {} /data/jobs/file/obj1 \;
Details:
Find all files that contains the string. grep -l will list the files.
find . -type f -exec grep -lr "Qtr_1_results" {} \;
Result set from first part is a list of files. Copy each files from the result to destination.
-exec cp -r {} /data/jobs/file/obj1 \;

Rename all files in multiple folders with some condition in single linux command os script.

I have multiple folders with multiple files. I need to rename those files with the same name like the folder where the file stored with "_partN" prefix.
As example,
I have a folder named as "new_folder_for_upload" which have 2 files. I need to convert the name of these 2 files like,
new_folder_for_upload_part1
new_folder_for_upload_part2
I have so many folders like above which have multiple files. I need to convert all the file names as I describe above.
Can anybody help me to find out for a single linux command or script to do this work automatically?
Assuming bash shell, and assuming you want the file numbering to restart for each subdirectory, and doing the moving of all files to the top directory (leaving empty subdirectories). Formatted as script for easier reading:
find . -type f -print0 | while IFS= read -r -d '' file
do
myfile=$(echo $file | sed "s#./##")
mydir=$(dirname "$myfile")
if [[ $mydir != $lastdir ]]
then
NR=1
fi
lastdir=${mydir}
mv "$myfile" "$(dirname "$myfile")_part${NR}"
((NR++))
done
Or as one-line command:
find . -type f -print0 | while IFS= read -r -d '' file; do myfile=$(echo $file | sed "s#./##"); mydir=$(dirname "$myfile"); if [[ $mydir != $lastdir ]]; then NR=1; fi; lastdir=${mydir}; mv "$myfile" "$(dirname "$myfile")_part${NR}"; ((NR++)); done
Beware. This is armed, and will do a bulk renaming / moving of every file in or below your current work directory. Use at your own risk.
To delete the empty subdirs:
find . -depth -empty -type d -delete

Rename all files within a folder prefixed with foldername [duplicate]

This question already has answers here:
Rename filename to another name
(3 answers)
Closed 6 years ago.
I have a bunch of directories each having multiple files.
dir1
|- part1.txt
|- part2.txt . . .
dir2
|- part1.txt
|- part2.txt . . .
I want to rename the internal files (part1.txt and so on) to something like (dir1_part1.txt). How can this be done in ubuntu?
This question explains how suffix prefix can be added or removed. But how do I add a prefix as a Directory Name?
There is a tool called perl-rename sometimes called rename, not to be confused with rename from util-linux. This tool takes a perl expression and renames accordently:
perl-rename 's~/~_~' dir1/* dir2/*
The above will rename and move all files in dir1 and dir2 to the following:
dir1/file1 -> dir1_file1
dir1/file2 -> dir1_file2
dir1/file3 -> dir1_file3
You can play with the regex online
A simple bash script using find and parameter-expansion for finding the directory name.
#!/bin/bash
find . -name "*.csv" -type f -printf '%f\n' |
while read -r x; do
mv -v "$x" "${PWD##*/}_$x"
done
To handle files with special characters:-
To handle file-names that contain newlines or other types of white space or other special characters, am adopting -print0 from find and reading them with a de-limiter '':-
Am using parameter-expansion again, to strip leading characters ./ from find command.
#!/bin/bash
find . -name "*.csv" -type f -print0 |
while IFS= read -r -d '' x; do
x="${x:2}"
mv -v "$x" "${PWD##*/}_$x"
done
A working example:-
[dude#csv_folder]$ ls *.csv
1.csv 2.csv 3.csv 4.csv
[dude#csv_folder]$ ./myScript.sh
`1.csv' -> `csv_folder_1.txt'
`2.csv' -> `csv_folder_2.txt'
`3.csv' -> `csv_folder_3.txt'
`4.csv' -> `csv_folder_4.txt'
Okay, here is a simple example.
$ mkdir dir{1..5}
$ touch dir{1..5}/part{1..5}.txt
# the command above create the files for testing
# then do the rename action
$ for f in dir*/*;do mv -v $f $(dirname $f)/$(dirname $f)_$(basename $f);done

Linux : combining the "ls" and "cp" command

The command
ls -l | egrep '^d'
Lists all the Directories in the CWD..
And this command
cp a.txt /folder
copies a file a.txt to the folder named "folder"
Now what should i do to combine the 2 command so that the file a.txt gets copied to all the folders in the CWD.
The cp command does not take several destinations, but you could always try:
for DEST in `command here` ; do cp a.txt "$DEST" ; done
The command inside the backticks could be a command that produces a list of directories on standard output, but I doubt that ls -l | egrep '^d' is such a command. Anyway, the title of your question being about combining ls and cp commands, this my answer. To actually achieve what you want to do, you would be better off using find.
Something like find . -maxdepth 1 -type d ! -name "." -exec cp a.txt {} \; may do what you actually want. The find command is a special case in that is has a -exec option to combine itself with other commands easily. You could also have used (but this other version fails when there are lots of directories):
for DEST in `find . -maxdepth 1 -type d ! -name "."` ; do cp a.txt "$DEST" ; done
Don't use ls in scripts. Use a wildcard instead.
You'll have to loop over the target directories, since cp copies to one destination at a time.
for d in */; do
if ! [ -h "${d%/}" ]; then
cp a.txt "$d"
fi
done
The pattern */ matches all directories in the current directory (unless their name starts with a .), as well as symbolic links to directories. The test over ${d%/} ($d without the final /) excludes symbolic links.

Resources