I have a large number of conflict files generated (incorrectly) by the dropbox service. These files are on my local linux file system.
Example file name = compile (master's conflicted copy 2013-12-21).sh
I would like to rename the file with its correct original name, in this case compile.sh and remove any existing file with that name. Ideally this could be scripted or in such a way to be recursive.
EDIT
After looking over the solution provided and playing around and further research I cobbled together something that works well for me:
#!/bin/bash
folder=/path/to/dropbox
clear
echo "This script will climb through the $folder tree and repair conflict files"
echo "Press a key to continue..."
read -n 1
echo "------------------------------"
find $folder -type f -print0 | while read -d $'\0' file; do
newname=$(echo "$file" | sed 's/ (.*conflicted copy.*)//')
if [ "$file" != "$newname" ]; then
echo "Found conflict file - $file"
if test -f $newname
then
backupname=$newname.backup
echo " "
echo "File with original name already exists, backup as $backupname"
mv "$newname" "$backupname"
fi
echo "moving $file to $newname"
mv "$file" "$newname"
echo
fi
done
all files from current directory:
for file in *
do
newname=$(echo "$file" | sed 's/ (.*)//')
if [ "$file" != "$newname" ]; then
echo moving "$file" to "$newname"
# mv "$file" "$newname" #<--- remove the comment once you are sure your script does the right thing
fi
done
or to recurse, put the following into a script that i'll call /tmp/myrename:
file="$1"
newname=$(echo "$file" | sed 's/ (.*)//')
if [ "$file" != "$newname" ]; then
echo moving "$file" to "$newname"
# mv "$file" "$newname" #<--- remove the comment once you are sure your script does the right thing
fi
then find . -type f -print0 | xargs -0 -n 1 /tmp/myrename (This is a bit hard to do on the command line without using an extra script because the file names contain blanks).
a small contribution:
I've had a problem this this script. The files with spaces in their name do not made a copy. So I modified line 17 :
-------cut-------------cut---------
if test -f "$newname"
-------cut-------------cut---------
This script displayed above is now outdated; the following works fine with the latest version of Dropbox running on Linux Mint at the time of writing:
#!/bin/bash
#modify this as needed
folder="./"
clear
echo "This script will climb through the $folder tree and repair conflict files"
echo "Press a key to continue..."
read -n 1
echo "------------------------------"
find "$folder" -type f -print0 | while read -d $'\0' file; do
newname=$(echo "$file" | sed 's/ (.*Case Conflict.*)//')
if [ "$file" != "$newname" ]; then
echo "Found conflict file - $file"
if test -f "$newname"
then
backupname=$newname.backup
echo " "
echo "File with original name already exists, backup as $backupname"
mv "$newname" "$backupname"
fi
echo "moving $file to $newname"
mv "$file" "$newname"
echo
fi
done
You can use the tool Dropbox Conflict Fix. It resolved all my conflicted copy files.
Related
How to rename a bunch of files in a directory to be param-case with the hyphen?
Here's one that does it in JavaScript, but I'm not sure how to go about this in bash.
Below is an option in bash:
for file in ./* ; do mv "$file" "$(echo $file | sed 's/\(.\)\([A-Z]\)/\1-\2/g' | tr '[:upper:]' '[:lower:]')" ; done
An alternative with perl:
for file in ./* ; do mv "$file" "$(echo $file | perl -ne 'print lc(join("-", split(/(?=[A-Z])/)))')" ; done
I am writing a script that renames *.MP4 files on an inserted SD card and then rsyncs them.
The directory with the *.MP4 files does not always have the same name:
eg: it could be /DCIM/123_PANA/ or /DCIM/141_PANA/ etc
So I'm trying to write a script that will see what folders are in the /DCIM path, and rename all the *.MP4 files, (there is also a MISC folder in this path which I suspect is causing the issue)
I am using a couple of variables to rename the files also
What I have is:
for f in /media/pi/LUMIX/DCIM/*; do
if [ -d "$f" ]; then
echo $f
for file in $(find $f -name 'P*.MP4')
do
echo $file ">" $(dirname "${file}")/$(date +"%d")$cardname$(basename $file)
mv $file $(dirname "${file}")/$(date +"%d")$cardname$(basename $file)
done
fi
done
But what seems to happen is I end up with a single file with the prefix only (say 08_nb1_) in the _PANA folder, all the others have been deleted. Obviously this is not my desired result!
UPDATE:
$cardname is of the format _nb2_
When I do as asked replace mv with echo here is the output:
/media/pi/LUMIX/DCIM/141_PANA
mv /media/pi/LUMIX/DCIM/141_PANA/P1410192.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410192.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410193.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410193.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410194.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410194.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410195.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410195.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410196.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410196.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410197.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410197.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410198.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410198.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410199.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410199.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410200.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410200.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410201.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410201.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410202.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410202.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410203.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410203.MP4
mv /media/pi/LUMIX/DCIM/141_PANA/P1410204.MP4 /media/pi/LUMIX/DCIM/141_PANA/09_nb2_P1410204.MP4
/media/pi/LUMIX/DCIM/MISC
OK I fixed it by filtering the additional directory names and limiting to only the ones with *_PANA - which solved the issue. I also added a the rsync part and demounted the SD card (if required using Zenity)
A text file placed on the SD card identifies it as a unique card giving each file a unique name when rsyncing it to the backup folder. Renaming on the SD card means
that it can still be used an written to if not full, but we then know which files have been backed up.
Very useful in the field when filming with multiple cards, crews. All running on a Rpi4
for f in /media/pi/LUMIX/DCIM/*_PANA/; do
if [ -d "$f" ]; then
echo "$f"
for file in $(find $f -wholename '*_PANA/P*.MP4')
do
mv "$file" $(dirname "${file}")/$(date +"%d")"$cardname"$(basename "${file}")
done
rsync --stats -u --progress "$f"/*.MP4 /media/pi/VDRIVE/ | tee /home/pi/Documents/ytu/rsync.txt | zenity --icon-name="dialog-warning" \
--width=300 --progress --pulsate --auto-close --auto-kill \
--title="Copying $sdn"
zenity --question --text="Unmount Card?"
if [ $? = 0 ]; then
umount /media/pi/LUMIX
else
exit
fi
fi
done
I was trying to copy all files of a certain filetype from all subfolders to one place. Unfortunately, this might cause collisions, if two files have the same name from two different subfolders.
I was using
find ./ -name '*.jpg' -exec mv -u '{}' . \;
How can I adjust this to automatically rename files (e.g. append "_1") to avoid collisions.
Or better: check if the files are the same (e.g. same size) beforehand. If yes, ignore (overwrite would be fine, too). If No, rename to avoid collision.
Suggestion would be appreciated. Thanks!
You could check before moving each individual file. Here I've used cksum to compare, which returns both the filesize and a simple checksum.
find ./ -name '*.jpg' -print0 |
while read -d '' -r path; do
file=$(basename "$path")
if [[ -e $file ]]; then
if [[ $(cksum "$file" | awk '{print $1 $2}') = $(cksum "$path" | awk '{print $1 $2}') ]]; then
continue
fi
read -n 1 -p "File '$file' would be overwritten by '$path', continue? (y/N) " -r prompt </dev/tty
if [[ $prompt != [Yy] ]]; then
continue
fi
fi
mv -f -v "$path" "$file"
done
I have a huge directory structure of movie files. For analysis of that structure I want to copy the entire directory structure, i.e. folders and files however I don't want to copy all the movie files while I want to keep there file names. Ideally I get zero-byte files with the original movie file name.
I tried to and then rsync to my remote machine which didn't fetch the link files.
Any ideas how to do that w/o writing scripts?
You can use find:
find src/ -type d -exec mkdir -p dest/{} \; \
-o -type f -exec touch dest/{} \;
Find directory (-d) under (src/) and create (mkdir -p) them under dest/ or (-o) find files (-f) and touch them under dest/.
This will result in:
dest/src/<file-structre>
You can user mv creatively to resolve this issue.
Other (partial) solution can be achieved with rsync:
rsync -a --filter="-! */" sorce_dir/ target_dir/
The trick here is the --filter=RULE option that excludes (-) everything that is not (!) a directory (*/)
On ubuntu you can try:
cp -r --attributes-only <source_dir> <target_dir>
It doesn't copy file data.
From manpage of cp
--attributes-only
don't copy the file data, just the attributes
Note: I'm not sure this option available for other distributions, if anybody can confirm please update the answer.
I needed an alternative to this to sync only the file structure:
rsync --recursive --times --delete --omit-dir-times --itemize-changes "$src_path/" "$dst_path"
This is how I realized it:
# sync source to destination
while IFS= read -r -d '' src_file; do
dst_file="$dst_path${src_file/$src_path/}"
# new files
if [[ ! -e "$dst_file" ]]; then
if [[ -d "$src_file" ]]; then
mkdir -p "$dst_file"
elif [[ -f $src_file ]]; then
touch -r "$src_file" "$dst_file"
else
echo "Error: $src_file is not a dir or file"
fi
echo -n "+ "
ls -ld "$src_file"
# modification time changed (files only)
elif [[ -f $dst_file ]] && [[ $(date -r "$src_file") != $(date -r "$dst_file") ]]; then
touch -r "$src_file" "$dst_file"
echo -n "+ "
ls -ld "$src_file"
fi
done < <(find "$src_path" -print0)
# delete files in destination if they disappeared in source
while IFS= read -r -d '' dst_file; do
src_file="$src_path${dst_file/$dst_path/}"
# file disappeard on source
if [[ ! -e "$src_file" ]]; then
delinfo=$(ls -ld "$dst_file")
if [[ -d "$dst_file" ]] && rmdir "$dst_file" 2>/dev/null; then
echo -n "- $delinfo"
elif [[ -f $dst_file ]] && rm "$dst_file"; then
echo -n "- $delinfo"
fi
fi
done < <(find "$dst_path" -print0)
As you can see I use echo and ls to display changes.
ls > listOfMovie.txt; You will have the list of your films in a .txt file
.For multiple directories see the man page.
How to change extension of all *.dat files in a directory to *.txt.
Shell script should take the directory name as an argument. Can
take multiple directories as arguments. Print the log of command
result in appending mode with date and timestamp.
Bash can do all of the heavy lifting such as extracting the extension and tagging on a new one. For example:
for file in $1/*.dat ; do mv "$file" "${file%.*}.txt" ; done
Batch File Rename By File Extension in Unix
# change .htm files to .html
for file in *.htm ; do mv $file `echo $file | sed 's/\(.*\.\)htm/\1html/'` ; done
# change .html files to .htm
for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1htm/'` ; done
#change .html files to .shtml
for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1shtml/'` ; done
#change .html files to php
for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1php/'` ; done
so ==>
# change .dat files to .txt
for file in *.dat ; do mv $file `echo $file | sed 's/\(.*\.\)dat /\1txt/'` ; done
#!/bin/bash
for d in $*; do
for f in $(ls $d/*.dat); do
echo $(date) $(mv -v $f ${f%.dat}.txt)
done
done
Output redirection should be done by the shell when running the script
Leaving out argument validity checks
Simple script:
#!/bin/bash
if [ $# -lt 2 ] then
echo "Usage `basename $0` <any number of directories space separated>"
exit 85 # exit status for wrong number of arguments.
fi
for directories
do
for files in $(ls $directories/*.dat); do
echo $(date) $(mv -v $files ${files%.dat}.txt)
done
done
The first for loop by default loops on the $# i.e. command-line arguments passed.
Follow Pben's solution, if your filename contains blank space, you should use double quotation marks to the variable like the following:
#remove the space in file name
#example file name:19-014-0100.mp3 .mp3
#result file name:19-014-0100.mp3
$ for file in *.mp3 ;
do target=`echo "$file" | sed 's/ //g'`;
echo "$target";
mv "$file" "$target";
done;
#remove the duplicate file extension in file name
#example file name:19-014-0100.mp3.mp3
#result file name:19-014-0100.mp3
$ for file in *.mp3 ;
do target=`echo "$file" | sed 's/\.mp3\.mp3$/.mp3/g'`;
echo "$target";
mv "$file" "$target";
done;
To rename (changing extention) all my html files on epub files I use this command line :
find . -name "*.html*" -exec rename -v 's/\.html$/\.epub/i' {} \;
Script, first finds the names of the given extensions.
It removes the extension from names. Then adds backslash()
for identification of terminal.
Then the 'mv' command executed.
Here the '.temp' folder is used to hide the process from user,
in GUI.
#!/bin/sh
if [ $# -ne 3 ]
then
echo "Usage: ./script folder current_extension modify_extension"
exit
fi
mkdir .temp
find $1 -name "*.$2" > .temp/output_1 && sed "s/$2//" .temp/output_1 > .temp/output_2 && sed -e "s/[ \t]/\\\ /g" .temp/output_2 > .temp/output_3
while read line
do
mv -v "$line""$2" "$line""$3"
done < .temp/output_3
rm -rf .temp
The output files are saved inside the '.temp' folder,later the '.temp' folder is removed.
The top voted answer didn't really work for me. I may have been doing something wrong. My scenario was trying to create a file with the original name, but with the date appended to it, along with changing the extension from .xslx to .csv. This is what worked for me:
csvname=`echo $xlsx |sed 's/\.xlsx//'`"-$now"`echo $xlsx | sed 's/\(.*\.\)xlsx/\.csv/'`
So, for all the .dat files in a directory (without the date addition), you could run something like this:
for i in *.dat
do mv $i `echo $i |sed 's/\.dat//'``echo $i | sed 's/\(.*\.\)dat/\.txt/'`
done
From the above, this section of code just removed the extension:
echo $i |sed 's/\.dat//'
And this section changes the .dat to .txt:
echo $i | sed 's/\(.*\.\)dat/\.txt/'
And by bumping them next to each other, it concatenates the two outputs into the filename. It's like doing this:
mv [filename][.dat] [filename] + [.txt]
Though, I did use STDOUT instead of the 'mv' command.
Following command to change file extention .c to .h
find . -depth -name "*.c" -exec sh -c 'dname=$(dirname {}) && fname=$(basename {} .c) && mv {} $dname/$fname.h' ";"
change js to cjs extension files recursively:
cd dist # where you place your .js
for file in $(find . -type f -name "*.js"); do mv "$file" "${file%.*}.cjs"; done