How to rename a group of similar files with only part of file name? - bash

I have a group of files:
Ursus_fibroblast_ACT_34_CT0_adak_HJ_EV_S45_L002_R1_001_val_1.fq.gzAligned.out.sam
Ursus_fibroblast_ACT_34_CT12_adak_HJ_EV_S49_L002_R1_001_val_1.fq.gzAligned.out.sam
Ursus_fibroblast_ACT_34_CT0_adak_HJ_EV_S45_L002_R1_001_val_1.fq.gzAligned.out.sam
Ursus_fibroblast_ACT_34_CT12_adak_HJ_EV_S49_L002_R1_001_val_1.fq.gzAligned.out.sam
Ursus_fibroblast_ACT_34_CT15_adak_HJ_EV_S50_L002_R1_001_val_1.fq.gzAligned.out.sam
I would like to rename them with only this part of the name plus the extension "Aligned.out.sam":
"ACT_34_CT15_adak_HJ_EV_S50" "ACT_34_CT12_adak_HJ_EV_S49" and so on.
I have a start of a script so far but I am unsure of what to do now....I am obviously new to coding so if you need more information please let me know.
files={*.sam}
for i in $files
echo $i
mv -i $i

If your files are in the same directory this command will do the job.
for x in *.sam; do mv $x ${x%.sam}.Aligned.out.sam;done

while read file
do
target=${file//Ursus_fibroblast_}
target=${target//_L002*}
echo mv "$file" "$target.Aligned.out.sam" # this is an echo
done < <(find . -type f -name "*.sam")
mv ./Ursus_fibroblast_ACT_34_CT0_adak_HJ_EV_S45_L002_R1_001_val_1.fq.gzAligned.out.sam ./ACT_34_CT0_adak_HJ_EV_S45.Aligned.out.sam
mv ./Ursus_fibroblast_ACT_34_CT12_adak_HJ_EV_S49_L002_R1_001_val_1.fq.gzAligned.out.sam ./ACT_34_CT12_adak_HJ_EV_S49.Aligned.out.sam
mv ./Ursus_fibroblast_ACT_34_CT15_adak_HJ_EV_S50_L002_R1_001_val_1.fq.gzAligned.out.sam ./ACT_34_CT15_adak_HJ_EV_S50.Aligned.out.sam

Related

Renaming all files in a folder with a prefix and in ascending order

How does one rename
random_files.jpg
that\ may\ contain\ spaces.jpg
and_differ_in_extensions.mp4
to
PREFIX_1.jpg
PREFIX_2.jpg
PREFIX_3.mp4
via bash script? More formally, how do I rename all files in a directory into an ordered list of form PREFIX_N.ext where .ext is preserved from the original filename.
My attempt below
for f in *; do
[[ -f "$f" ]] && mv "$f" "PREFIX_$f"
done
changes only prefixes.
You can use this in a for loop using find:
while IFS= read -rd '' file; do
ext="${file##*.}"
echo mv "$file" "PREFIX_$((++i)).$ext"
done < <(find . -type f -name '*.*' -maxdepth 1 -print0)
Once satisfied with the output, remove echo before mv command.
You can loop over the files using *, and then access them with a quoted var to preserve all the special characters.
You can then use parameter expansion to remove the start of the file up to ., and append that to your new filename.
x=1;for i in *;do [[ -f "$i" ]] && mv "$i" "PREFIX_$((x++)).${i##*.}";done
If you know x isn't already set though you can remove the assignment at the start and change $((x++)) to $((++x))

How to print the number of locations of file found

Prompt the user for a file name, without the path (Ex: xyz.out)
- Using the find command, provide the full path to the file
- At the end, “print number of locations of that file found”
- If it’s not found, then display “not found
and this is my script
#! /bin /bash
echo "please enter your file name"
read filename
if [ -f $filename ];
then
echo "file $filename found"
find $PWD -type f | grep $filename
#find "$(cd ..; pwd)" -name $filename
else
echo "file $filename was not found"
fi
but the thing is At the end, i need to “print number of locations of that file found”
help me out with this
Something like this to get the count:
find $PWD -type f -name $filename 2>/dev/null | wc -l
This should work:
find "$PWD" -type f -name "$fname" |grep "" -c
In trying to keep it as short as possible, one approach with Posix shell would be to fill a temporary file with the file names returned by find, cat the file to provide your output, and use wc to provide the line count (note: you use your own pattern instead of "*cmpf*" shown below):
$ find . -name "*cmpf*" -printf "%P\n" >tmp; cat tmp; c=$(wc -l <tmp); \
rm tmp; printf "[%s] files found\n" $c
cmpf1f2.c
cmpf1f2_2.c
bin/cmpf1f2_2
bin/cmpf1f2
snip/cmpf1f2_notes.txt
cmpf1f2_for.c
[6] files found
If bash is available, another approach is to read the matching files into an array and then use the number of elements as your count. Example:
$ a=( $(find . -name "*cmpf*" -printf "%P\n") ); printf "%s\n" ${a[#]}; \
printf -- "--\n'%s' files found.\n" ${#a[#]}
cmpf1f2.c
cmpf1f2_2.c
bin/cmpf1f2_2
bin/cmpf1f2
snip/cmpf1f2_notes.txt
cmpf1f2_for.c
--
'6' files found.
Both approaches give you both the files and directories in which they reside as well as the count of the files returned.
Note: if you would like ./ before each file and directory names, use the %p format instead of %P above.

Bash: Find, copy and rename files

I am trying to copy files (on the same server) created in the last 24 hours using the filename (Unix timestamp):
find /srv/docs/files/ -type f -iname '*.pdf' -mtime -1 -exec cp {} /srv/docs/pdf \;
However, I would like to extend this further. I would like to accomplish the following:
All files are named in this manner 1425787200.pdf. I would like to rename the file Sunday-0400.pdf
I would would like to create a new directory /srv/docs/pdf/day/time/ .
A file named 1425787200.pdf would end up in /srv/docs/pdf/Sunday/0400/Sunday-0400.pdf
Additionally, if the file already exists, an incremental number should be added to the file. eg Sunday-0400-1.pdf, Sunday-0400-2.pdf
Any help would be appreciated.
To change file name 1425787200.pdf to /srv/docs/pdf/Sunday/0400/Sunday-0400.pdf use something like this:
#!/usr/bin/bash
file=1425787200.pdf
day=$(date +"%A" -d "#${file%.*}")
time=$(date +"%H%M" -d "#${file%.*}")
new_file=/srv/docs/pdf/$day/$time/$day-$time.pdf
if [ -e "$new_file" ]; then
num_file=${new_file%.*}
num=1
while [ -e "${num_file}-${num}.pdf" ]; do
num=$(( num + 1 ))
done
new_file=${num_file}-${num}.pdf
fi
mv $file $new_file
this will also number duplcates.

Compare files with the same name

I created script to compare files in folder (with the name .jpg and without it BUT with the same NAME).The problem that script searches for files in ONE directory ,not in SubDirectories!How i can fix it?
for f in *
do
for n in *.jpg
do
tempfile="${n##*/}"
echo "Processing"
echo "${tempfile%.*}"
echo "$f"
if [[ "${tempfile%.*}" = $f ]]
then
echo "This files have the same name!"
//do something here
else
echo "No files"
fi
done
done
This requires bash version 4 for associative arrays.
shopt -s globstar nullglob extglob
declare -A jpgs
for jpg in **/*.jpg; do
name=$(basename "${jpg%.jpg}")
jpgs["$name"]=$jpg
done
for f in **/!(*.jpg); do
name=$(basename "$f")
if [[ -n ${jpgs["$name"]} ]]; then
echo "$f has the same name as ${jpgs["$name"]}"
fi
done
You can also try using find
find . -type f -name "*.sh" -printf "%f\n" | cut -f1 -d '.' > jpg.txt
while read line
do
find . -name "$line.*" -print
done < jpg.txt

Renaming Multiples Files To delete first portion of name

I have a list of files like so :
10_I_am_here_001.jpg
20_I_am_here_003.jpg
30_I_am_here_008.jpg
40_I_am_here_004.jpg
50_I_am_here_009.jpg
60_I_am_here_002.jpg
70_I_am_here_005.jpg
80_I_am_here_006.jpg
How can I rename all the files in a directory, so that I can drop ^[0-9]+_ from the filename ?
Thank you
Using pure BASH:
s='10_I_am_here_001.jpg'
echo "${s#[0-9]*_}"
I_am_here_001.jpg
You can then write a simple for loop in that directory like this:
for s in *; do
f="${s#[0-9]*_}" && mv "$s" "$f"
done
Using rename :
rename 's/^[0-9]+_//' *
Here's another bash idea based on files ending .jpg as shown above or whatever>
VonBell
#!/bin/bash
ls *.jpg |\
while read FileName
do
NewName="`echo $FileName | cut -f2- -d "_"`"
mv $FileName $NewName
done
With bash extended globbing
shopt -s extglob
for f in *
do
[[ $f == +([0-9])_*.jpg ]] && mv "$f" "${f#+([0-9])_}"
done

Resources