I have this string:
2013/07./penguin pingouin pinguino 365.png
...that I want to effectively be renamed to
2013/07./penguin pingouin pinguino 365${RANDOM}.png
I'm thinking that sed might be able to insert random bits 4 spaces inward from the last character in the string. I don't know how to do that (if it's even possible or the best method).
Background: This is part of a picture sorting script that I'm trying to incorporate a rename ability when it finds duplicates. The extension is not always .png, but it will always be three characters.
Try something like:
for file in *; do
ext="${i##*.}";
mv "$file" "${file%.*}${random}.${ext}";
done
$ random="my random stuff" #
$ touch "penguin pingouin pinguino 365.png"
$ ls
penguin pingouin pinguino 365.png
$ for file in *; do
ext="${i##*.}"; mv "$file" "${file%.*}${random}.${ext}";
done
$ ls
penguin pingouin pinguino 365my random stuff.png
Here's another way to backup files into a directory:
moveto () {
file=$1
if [[ -f "$file" ]]; then
echo "no such file: $file"
return 1
fi
dir=$2;
if [[ -d "$dir" ]]; then
echo "no such directory: $dir"
return 1
fi
target="$dir/$(basename "$file")"
if [[ -f "$target" ]]; then
base=${target%.???}
ext=${target##*.}
prev=("$base"_*)
for ((i=${#prev[#]}-1; i>=0; i--)); do
if [[ ${prev[i]} =~ "$base"_0*([0-9]+) ]]; then
n=${BASH_REMATCH[1]}
mv "${prev[i]}" "$(printf "%s_%03d.%s" "$base" $((n+1)) "$ext")"
fi
done
mv "$target" "$base"_001.$ext
fi
mv "$file" "$target"
}
The first time you "moveto" a file to a dir (moveto file.txt backups), you get "backups/file.txt"
The 2nd time, you'll have "backups/file.txt" and "backups/file_001.txt"
The 3rd time, you'll have "backups/file.txt", "backups/file_001.txt" and "backups/file_002.txt"
And so on.
The following snippet should do what you need in sed sed -r 's/(.[a-zA-Z]+$)/$RANDOM\1'
Related
I would like to display a character at the beginning of all folder names when typing the ls command.
So instead of this:
ls
Folder-1 Folder-2 file.txt
It displays this:
ls
πFolder-1 πFolder-2 file.txt
Is there a script I can write in my .bash_profile to do this?
You can make a custom script that makes it for you:
#!/bin/bash
lsmod=($(ls)) # Convert ls output to an array
for folder in ${lsmod[#]}; do # Iterate over ls results
if [[ -d $folder ]]; then # If this is a folder then...
echo "=> $folder" # Put your char
else # If not, display normally
echo "$folder"
fi
done
Folders are pointed out with a =>. Hope this helps.
One line approach:
for i in `ls`; do echo $([[ -d "$i" ]] && echo "=> $i" || echo "$i"); done;
I'm writing very simple bash script to change encoding of
.html files and want to handle directories recursively.
The function working properly for first level directory only.
Can you tell me where I'm wrong? Here is me code.
#!/bin/bash
handleFiles () {
local REGEXP='.+\.html$'
echo $1
for f in $1/*
do
if [[ -d $f ]]
then
handleFiles "$f"
elif [[ $f =~ $REGEXP ]]
then
echo "Converting $f"
enconv -L bg -x UTF-8 "$f"
fi
done
}
# The script show all .html files in test
# enter into subdirectory but not working ..
handleFiles "test"
Here is structure of test directory:
test$ tree
.
βββ test.html
βββ Untitled Folder
βββ test1.html
1 directory, 2 files
When I run the script I get following output:
./converter.sh
test
Converting test/test.html
test/Untitled Folder
To be the whole story I post my final solution. I hope this will be useful to someone with a similar problem.
#!/bin/bash
########################################################
# This bash script assume directory as a argument
# and convert all .html,js and xml files from
# windows-1251 encoding into utf-8 encoding.
# #author Georgi Naumov
# #email gonaumov#gmail.com for contacts and
# suggestions.
########################################################
if [[ $# -ne 1 ]] ; then
echo "Usage $0 <<directory to change encoding reqursively>>"
exit 1
fi
handleFiles () {
local REGEXP='.+\.(html|js|xml)$'
for f in "$1"/*
do
if [[ -d "$f" ]]
then
handleFiles "$f"
elif [[ "$f" =~ $REGEXP ]]
then
echo "Converting $f"
enconv -L bg -x UTF-8 "$f"
fi
done
}
handleFiles "$1"
The whole approach is rather more complicated than necessary. I recommend using find:
find test -name '*.html' -exec enconv -L bg -x UTF-8 '{}' \;
If you want to do it manually, you have to put $f in double quotes everywhere (i.e., "$f"), or it will break if a directory contains spaces, as you have noticed, because the shell will expand it into two (or more, as the case may be) separate tokens.
Quote also $1 to handle whitespaces (e.g. Untitled Folder):
for f in "$1"/*
I currently have this code:
listing=$(find "$PWD")
fullnames=""
while read listing;
do
if [ -f "$listing" ]
then
path=`echo "$listing" | awk -F/ '{print $(NF)}'`
fullnames="$fullnames $path"
echo $fullnames
fi
done
For some reason, this script isn't working, and I think it has something to do with the way that I'm writing the while loop / declaring listing. Basically, the code is supposed to pull out the actual names of the files, i.e. blah.txt, from the find $PWD.
read listing does not read a value from the string listing; it sets the value of listing with a line read from standard input. Try this:
# Ignoring the possibility of file names that contain newlines
while read; do
[[ -f $REPLY ]] || continue
path=${REPLY##*/}
fullnames+=( $path )
echo "${fullnames[#]}"
done < <( find "$PWD" )
With bash 4 or later, you can simplify this with
shopt -s globstar
for f in **/*; do
[[ -f $f ]] || continue
path+=( "$f" )
done
fullnames=${paths[#]##*/}
I am able to rename files numerically, in place, in multiple folders. However, it is not the result I am looking for. My file structure looks as follows:
Pictures-
Vacation-
img.001.jpg
img.002.jpg
img.003.jpg
Holidays-
img.004.jpg
img.005.jpg
img.006.jpg
Fun-
img.007.jpg
What I'd like to achieve is:
Pictures-
Vacation-
img.001.jpg
img.002.jpg
img.003.jpg
Holidays-
img.001.jpg
img.002.jpg
img.003.jpg
Fun-
img.001.jpg
So far I have come up with the following:
a=1
for i in $vm/Holiday/*; do
new=$(printf "%03d.jpg" ${a})
mv ${i} $vm/Holiday/${new}
let a=a+1
done
How can I achieve my desired result without having to separately run this on every single directory within my pictures folder?
Take your version and make it iterate over the folders as well.
#!/bin/bash
for dir in ~/code/stack/Pictures/*; do
[ -d "${dir}" ] || continue
i=1
for img in "${dir}"/*.jpg; do
[ -e "${img}" ] || break
new="$(printf "%03d.jpg" "${i}")"
echo mv "${img}" "$(dirname "${img}")/${new}"
((i++))
done
done
Change the location of your Pictures folder and dryrun with the echo in place first. Is that what you wanted...?
try this
ls > folders #cat top folders into folders
while read folder
do
cd $folder #go to vacation folder for example
i=0
ls *.jpg > files
while read line
do
mv $line img.$i.jpg #rename files according to your need
i=$(($i+1))
done < "files"
rm files
cd ..
done < "folders"
rm folders
#!/bin/bash
function renameImages {
local i=1;
for oldFile in * ; do
if [ -d "$oldFile" ] ; then
pushd "$oldFile" >/dev/null
renameImages
popd >/dev/null
elif [ "${oldFile##*.}" == "jpg" ] ; then
newFile=$(printf img.%03d.jpg $i)
echo "$PWD/$oldFile -> $PWD/$newFile"
i=$((i+1))
fi
done
}
renameImages
This won't actually rename any files, but instead it will print on screen how it would.
If you're happy with what it does, change
echo "$PWD/$oldFile -> $PWD/$newFile"
to
mv "$PWD/$oldFile" "$PWD/$newFile"
NOTE: The first edit of this answer would rename all files, .jpg or not. This version only renames .jpgs.
#!/bin/bash
a=1
for i in $vm/Vacation/*; do
new=$(printf "%04d.jpg" ${a})
mv ${i} $vm/Vacation/${new}
let a=a+1
done
b=1
for i in $vm/Holiday/*; do
new=$(printf "%04d.jpg" ${b})
mv ${i} $vm/Holiday/${new}
let b=b+1
done
c=1
for i in $vm/Fun/*; do
new=$(printf "%04d.jpg" ${c})
mv ${i} $vm/Fun/${new}
let c=c+1
done
This is long and tedious, not ideal, but it works. With years of folders to sort and add pictures to as I come across them, a much shorter solution would have been accepted.
I need to convert a lot of PNG files in many folders and process crop files separately to make thumbnails 100x100 px for just the "crop" files.
File naming is:
????_thumb.png
????_snapshot.png
????_crop.png
where ???? is a number.
My script so far is working to do conversions just fine,
however I need to detect when a "crop" file is reached and
then call ImageMagick and create a 100x100px thumbnail from it named ????_crop_th.png
I can't seem to figure how to detect on a wildcard ????_crop.png.
My script so far:
#!/bin/bash
BASE64=/root/scripts/base64
logfile=/root/tester/convert_failed.txt
goodfile=/root/tester/goodfile.txt
proc_dir=/root/tester/testing
temp_file=/root/tester/temp.png
b64=/root/tester/b64.txt
cd $proc_dir
for i in *
do
if [ -d $i ]
then
for j in $i/*.png
do
if [ -f $j ]
then
#just get files name without extension
fname=`echo $j | cut -d'.' -f1`
#perform operations
cp $j ${fname}.b64
$BASE64/base64 -d $j $temp_file
if [ $ -eq 0 ]
then
cp $temp_file $j
echo $j >> $goodfile
rm -f ${fname}.b64
fi
fi
done
fi
done
`find $proc_dir -name *.b64 -print >$b64`
sort $logfile -o $logfile
sort $goodfile -o $goodfile
sort $b64 -o $b64
Any help is well appreciated.
There are a few things that your script does less-than-perfectly, as well as some redundancies.
I also don't see anything in your script that uses Imagemagick to generate thumbnails from *_crop.png files, which is theoretically what this question is about
I vote for a rewrite. I have no idea if the following will be directly applicable to your situation, but the techniques should at least let you write better shell scripts.
#!/bin/bash
base64=/root/scripts/base64/base64
logfile=/root/tester/convert_failed.log
goodfile=/root/tester/goodfile.txt
proc_dir=/root/tester/testing
# The `cd` command will fail, if it fails. (Really.)
if cd "$proc_dir"; then
# Find all the PNGs in all subdirectories one level under our WD
for file in */*.png; do
# Do stuff (I have no idea what this is for...)
if $base64 -d "$file" "${file%.png}".b64 && mv "${file%.png}".b64 "$file"; then
echo "$file" >> $goodfile
else
printf '[%s] FAILED: %s\n' "${date '+%Y-%m-%d %T')" "$file" >> $logfile
fi
# Only make thumbnails if we need them
if [[ $file =~ _crop.png$ ]] && [[ ! -f "${file%_crop.png}_thumb.png" ]]; then
convert "$file" -scale 100x100 "${file%_crop.png}_thumb.png"
fi
done
fi
You can use regex matching or trailing substring removal, such as:
if [[ "$j" =~ _crop.png$ ]]
or
if [[ "${j%_crop.png}" != "$j" ]]
Also note that chopping off the extension is similarly easy:
fname=${j%.*}
Another useful bash feature is recursive globbing, so you don't need the nested loops and the specialized directory handling:
shopt -s globstar
for j in **/*.png