File path that modified by concatenating variables not working - bash

I'm trying to make this work. Please help.
folder="Test\ Folder"
path="/Volumes/Macintosh\ HD/Users/Shared/${folder}"
echo "$path"
if [ -d "$path" ]; then
echo "Yes"; else echo "No"
fi
This is the original script I'm working on.
echo in point
read inp
echo out point
read op
echo path
read ffolder
fName=`echo "$ffolder" | cut -d'/' -f1`
makejpgs () {
ffmpeg -y -i "${3}" -ss $1 -to $2 -vf fps=12 "$fName_%d.jpg"
}
path="/Volumes/PROJECTS/Main/${fName}"
files=$(find "$path" -type f -name "*story*")
echo "$files"
for i in $files; do
echo "$i"
makejpgs "$inp" "$op" "$i"
done
ffmpeg giving error when not using \ .

If you have a value "between quotes", then you do not need to escape\ spaces. So, change each \ into just .

You can escape special characters in your input.
echo path
read ffolder
ffolder=$(echo $ffolder | sed 's/[`~!##$%^&*() -_=+{}\|;:",<.>/?'"'"']/\\&/g')
On input of my desktop it will return my\ desktop and similarly for [my folder] it will return \[my\ folder\].

Related

Add character to file name if duplicate when moving with bash

I currently use a bash script and PDFgrep to rename files to a certain structure. However, in order to stop overriding if the new file has a duplicate name, I want to add a number at the end of the name. Keep in mind that there may be 3 or 4 duplicate names. What's the best way to do this?
#!/bin/bash
if [ $# -ne 1 ]; then
echo Usage: Renamer file
exit 1
fi
f="$1"
id1=$(pdfgrep -m 1 -i "MR# : " "$f" | grep -oE "[M][0-9][0-9]+") || continue
id2=$(pdfgrep -m 1 -i "Visit#" "$f" | grep -oE "[V][0-9][0-9]+") || continue
{ read today; read dob; read dop; } < <(pdfgrep -i " " "$f" | grep -oE "[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]")
dobsi=$(echo $dob | sed -e 's/\//-/g')
dopsi=$(echo $dop | sed -e 's/\//-/g')
mv -- "$f" "${id1}_${id2}_$(printf "$dobsi")_$(printf "$dopsi")_1.pdf"
Use a loop that checks if the destination filename exists, and increments a counter if it does. Replace the mv line with this:
prefix="${id1}_{id2}_${dob}_${dop}"
counter=0
while true
do
if [ "$counter" -ne 0 ]
then target="${prefix}_${counter}.pdf"
else target="${prefix}.pdf"
fi
if [ ! -e "$target" ]
then
mv -- "$f" "$target"
break
fi
((counter++))
done
Note that this suffers from a TOCTTOU problem, if the duplicate file is created between the ! -f "$target" test and the mv. I thought it would be possible to replace the existence check with using mv -n; but while this won't overwrite the file, it still treats the mv as successful, so you can't test the result to see if you need to increment the counter.

Converting FLAC file collection to ALAC in another directory with shell script

I have searched many forums and websites to create an ALAC collection from my FLAC collection with the same directory structure with no success. Therefore I coded my own shell script and decided to share here so others can use or improve on it.
Problems I wanted to solve:
Full automation of conversion. I did not want to go and run scripts
in each and every directory.
Recursive file search
Moving all the structure from one location to another by converting flac to alac and copying the artwork. nothing else.
I did not want flac and alac files in the same directory.(which the below
script I believe can do that)
Here is how the script turned out. It works for me, I hope it does for you as well. I am using Linux Mint and bash shell.
2014-12-08 - Made some changes and now it is working fine. Before it was creating multiple copies.
Usage is: ./FLACtoALAC.sh /sourcedirectory /targetdirectory
Here are some explanations:
Source: /a/b/c/d/e/ <- e has flac
/g/f/k <- k has artwork
/l <- l has mp3
Target: /z/u/v/g/f
when the command is run : ./FLACtoALAC.sh /a/b/ /z/u/
I want the structure look like:
/z/u/v/g/f <- f was already there
/c/d/e/ <- e had flac, so created with the tree following source (/a/b)
/c/g/f/k <- k had artwork, so created with the tree following source (/a/b)
not created l <- l did not have any of the png,jpg or flac files.
I do not want to create any directory that does not contain png, jpg or flac,
unless it is a parent to one of such those directories.
Now the updated code:
#!/bin/bash
if [[ $1 ]]
then
if [[ ${1:0:1} = / || ${1:0:1} = ~ ]]
then Source_Dir=$1
elif [[ ${1:0:1} = . ]]
then Source_Dir=`pwd`
else Source_Dir=`pwd`'/'$1
fi
else Source_Dir=`pwd`'/'
fi
if [[ $2 ]]
then
if [[ ${2:0:1} = / || ${2:0:1} = ~ ]]
then Target_Dir=$2
elif [[ ${2:0:1} = . ]]
then Target_Dir=`pwd`
else Target_Dir=`pwd`'/'$2
fi
else Target_Dir=`pwd`'/'
fi
echo "Source Directory : "$Source_Dir
echo "Target Directory : "$Target_Dir
typeset -i Source_Dir_Depth
Source_Dir_Depth=`echo $Source_Dir | grep -oi "\/" | wc -l`
typeset -i Target_Dir_Depth
Target_Dir_Depth=`echo $Target_Dir | grep -oi "\/" | wc -l`
echo "Depth of the Source Directory: "$Source_Dir_Depth
echo "Depth of the Target Directory: "$Target_Dir_Depth
echo "Let's check if the Target Directory exists, if not we will create"
typeset -i Number_of_depth_checks
Number_of_depth_checks=$Target_Dir_Depth+1
for depth in `seq 2 $Number_of_depth_checks`
do
Target_Directory_Tree=`echo ${Target_Dir} | cut -d'/' -f-${depth}`
if [[ -d "$Target_Directory_Tree" ]]
then
echo "This directory exists ("$Target_Directory_Tree"), moving on"
else
Create_Directory=`echo ${Target_Dir} | cut -d'/' -f-${depth}`
echo "Creating the directory/subdirectory $Create_Directory"
mkdir -pv "$Create_Directory"
fi
done
Directory_List=`find "${Source_Dir}" -type d -exec sh -c 'ls -tr -1 "{}" | sort | egrep -iq "*.(jpg|png|flac)$"' ';' -print`
oIFS=$IFS
IFS=$'\n'
for directories in $Directory_List
do
echo "Directories coming from the source : $directories"
typeset -i directories_depth
directories_depth=`echo $directories | grep -oi "\/" | wc -l`
echo "Number of sub-directories to be checked: $Source_Dir_Depth"
typeset -i number_of_directories_depth
number_of_directories_depth=$directories_depth+1
for depth in `seq 2 $number_of_directories_depth`
do
Source_Tree=`echo ${Source_Dir} | cut -d'/' -f-${depth}`
Subdirectory_Tree=`echo ${directories} | cut -d'/' -f-${depth}`
Subdirectory_Remaining_Tree=`echo ${directories} | cut -d'/' -f${depth}-`
echo "source tree : $Source_Tree"
echo "source tree : $Subdirectory_Tree"
if [[ $depth -le $Source_Dir_Depth && $Source_Tree = $Subdirectory_Tree ]]
then
echo "Common Directory, skipping ($Subdirectory_Tree)"
continue
else
export Targetecho=$(echo $Target_Dir | sed -e 's/\r//g')
export Destination_Directory=${Targetecho}${Subdirectory_Remaining_Tree}
echo "Destination directory is : $Destination_Directory"
export Sub_directories_depth=`echo $Destination_Directory | grep -oi "\/" | wc -l`
echo "Total destination depth : $Sub_directories_depth"
echo "Now we are checking target directory structure"
fi
break
done
echo "Gettin into the new loop to verify/create target structure"
typeset -i number_of_Sub_directories_depth
number_of_Sub_directories_depth=$Sub_directories_depth+1
for subdepth in `seq 2 $number_of_Sub_directories_depth`
do
Target_Subdirectory_Tree=`echo ${Destination_Directory} | cut -d'/' -f-${subdepth}`
if [[ $subdepth < $number_of_Sub_directories_depth && -d "$Target_Subdirectory_Tree" ]]
then
echo "Directory already exists in the destination ($Target_Subdirectory_Tree)"
elif [[ $subdepth < $number_of_Sub_directories_depth && ! -d "$Target_Subdirectory_Tree" ]]
then
echo "Creating the path in the destination ($Target_Subdirectory_Tree)"
mkdir -pv "$Target_Subdirectory_Tree"
elif [[ $subdepth -eq $number_of_Sub_directories_depth ]]
then
if [[ ! -d "$Destination_Directory" ]]
then
echo "Creating Directory: $Destination_Directory"
mkdir -pv "$Destination_Directory"
fi
echo "Directory already exists in the destination ($Destination_Directory)"
#Flac file processing starts here once the directory is found
Flac_File_List=`(shopt -s nocaseglob ; ls -tr "${directories}"/*.flac | sort)`
echo "List of files in $directories :"
echo $Flac_File_List
for flac_files in $Flac_File_List
do
echo "files : $flac_files"
typeset -i flac_file_depth
flac_file_depth=`echo $flac_files | grep -oi "\/" | wc -l`
flac_file_depth=$flac_file_depth+1
echo "flac_file_depth : $flac_file_depth"
Flac_File_Name=`echo ${flac_files} | cut -d'/' -f${flac_file_depth}`
echo "Flac_File Name : $Flac_File_Name"
Destination_File=${Destination_Directory}'/'${Flac_File_Name}
echo "will convert $Flac_File_Name from $flac_files to $Destination_File"
yes | ffmpeg -i "$flac_files" -vf "crop=((in_w/2)*2):((in_h/2)*2)" -c:a alac "${Destination_File%.flac}.m4a"
done
#Artwork file processing starts here once the directory is found
Art_File_List=`(shopt -s nocaseglob ; ls -tr "${directories}"/*.{png,jpg} | sort)`
echo "List of files in $directories :"
echo $Art_File_List
for art_files in $Art_File_List
do
echo "files : $art_files"
typeset -i art_file_depth
art_file_depth=`echo $art_files | grep -oi "\/" | wc -l`
art_file_depth=$art_file_depth+1
echo "file_depth : $art_file_depth"
Art_File_Name=`echo ${art_files} | cut -d'/' -f${art_file_depth}`
echo "File Name : $Art_File_Name"
Destination_File=${Destination_Directory}'/'${Art_File_Name}
echo "will copy $Art_File_Name from $art_files to $Destination_File"
cp "$art_files" "$Destination_File"
done
else
echo "did nothing!!!"
fi
done
done
IFS=$oIFS
feel free to change, improve, distribute.
Caglar
Try this out:
#!/bin/bash
src_dir="in"
dst_dir="out"
find ${src_dir} -type f -print0|while IFS= read -r -d '' src_file; do
dst_file=${src_file/$src_dir/$dst_dir}
echo "src_file=${src_file} dst_file=${dst_file}"
mkdir -pv `dirname $dst_file`
# use above variables and run convert command with it here
done
To test how it works:
mkdir in out
cd in
mkdir 1 2 3
find . -type d -exec touch {}/foo {}/bar {}/baz \;
cd ..
./run_my_script.sh
Now you only need to attach your convert function/script/command/whatever and improve it to read src_dir and dst_dir from the command line (I would recommend man bash - > getopts)

Bash script loop through subdirectories and write to file

I have no idea I have spent a lot of hours dealing with this problem. I need to write script. Script should loop recursively through subdirectories in current directory. It should check files count in each directory. If file count is greater than 10 it should write all names of these file in file named "BigList" otherwise it should write in file "ShortList". This should look like
---<directory name>
<filename>
<filename>
<filename>
<filename>
....
---<directory name>
<filename>
<filename>
<filename>
<filename>
....
My script only works if subdirecotries don't include subdirectories in turn.
I am confused about this. Because it doesn't work as I expect. It will take less than 5 minutes to write this on any programming language for my.
Please help to solve this problem , because I have no idea how to do this.
Here is my script
#!/bin/bash
parent_dir=""
if [ -d "$1" ]; then
path=$1;
else
path=$(pwd)
fi
parent_dir=$path
loop_folder_recurse() {
local files_list=""
local cnt=0
for i in "$1"/*;do
if [ -d "$i" ];then
echo "dir: $i"
parent_dir=$i
echo before recursion
loop_folder_recurse "$i"
echo after recursion
if [ $cnt -ge 10 ]; then
echo -e "---"$parent_dir >> BigList
echo -e $file_list >> BigList
else
echo -e "---"$parent_dir >> ShortList
echo -e $file_list >> ShortList
fi
elif [ -f "$i" ]; then
echo file $i
if [ $cur_fol != $main_pwd ]; then
file_list+=$i'\n'
cnt=$((cnt + 1))
fi
fi
done
}
echo "Base path: $path"
loop_folder_recurse $path
I believe that this does what you want:
find . -type d -exec env d={} bash -c 'out=Shortlist; [ $(ls "$d" | wc -l) -ge 10 ] && out=Biglist; { echo "--$d"; ls "$d"; echo; } >>"$out"' ';'
If we don't want either to count subdirectories to the cut-off or to list them in the output, then use this version:
find . -type d -exec env d={} bash -c 'out=Shortlist; [ $(ls -p "$d" | grep -v "/$" | wc -l) -ge 10 ] && out=Biglist; { echo "--$d"; ls -p "$d"; echo; } | grep -v "/$" >>"$out"' ';'

Bash: Native way to check if an entry is one line?

I have a find script that automatically opens a file if just one file is found. The way I currently handle it is doing a word count on the number of lines of the search results. Is there an easier way to do this?
if [ "$( cat "$temp" | wc -l | xargs echo )" == "1" ]; then
edit `cat "$temp"`
fi
EDITED - here is the context of the whole script.
term="$1"
temp=".aafind.txt"
find src sql common -iname "*$term*" | grep -v 'src/.*lib' >> "$temp"
if [ ! -s "$temp" ]; then
echo "ΓΈ - including lib..." 1>&2
find src sql common -iname "*$term*" >> "$temp"
fi
if [ "$( cat "$temp" | wc -l | xargs echo )" == "1" ]; then
# just open it in an editor
edit `cat "$temp"`
else
# format output
term_regex=`echo "$term" | sed "s%\*%[^/]*%g" | sed "s%\?%[^/]%g" `
cat "$temp" | sed -E 's%//+%/%' | grep --color -E -i "$term_regex|$"
fi
rm "$temp"
Unless I'm misunderstanding, the variable $temp contains one or more filenames, one per line, and if there is only one filename it should be edited?
[ $(wc -l <<< "$temp") = "1" ] && edit "$temp"
If $temp is a file containing filenames:
[ $(wc -l < "$temp") = "1" ] && edit "$(cat "$temp")"
Several of the results here will read through an entire file, whereas one can stop and have an answer after one line and one character:
if { IFS='' read -r result && ! read -n 1 _; } <file; then
echo "Exactly one line: $result"
else
echo "Either no valid content at all, or more than one line"
fi
For safely reading from find, if you have GNU find and bash as your shell, replace <file with < <(find ...) in the above. Even better, in that case, is to use NUL-delimited names, such that filenames with newlines (yes, they're legal) don't trip you up:
if { IFS='' read -r -d '' result && ! read -r -d '' -n 1 _; } \
< <(find ... -print0); then
printf 'Exactly one file: %q\n' "$result"
else
echo "Either no results, or more than one"
fi
Well, given that you are storing these results in the file $temp this is a little easier:
[ "$( wc -l < $temp )" -eq 1 ] && edit "$( cat $temp )"
Instead of 'cat $temp' you can do '< $temp', but it might take away some readability if you are not very familiar with redirection 8)
If you want to test whether the file is empty or not, test -s does that.
if [ -s "$temp" ]; then
edit `cat "$temp"`
fi
(A non-empty file by definition contains at least one line. You should find that wc -l agrees.)
If you genuinely want a line count of exactly one, then yes, it can be simplified substantially;
if [ $( wc -l <"$temp" ) = 1 ]; then
edit `cat "$temp"`
fi
You can use arrays:
x=($(find . -type f))
[ "${#x[*]}" -eq 1 ] && echo "just one || echo "many"
But you might have problems in case of filenames with whitespace, etc.
Still, something like this would be a native way
no this is the way, though you're making it over-complicated:
if [ "`wc -l $temp | cut -d' ' -f1`" = "1" ]; then
edit "$temp";
fi
what's complicating it is:
useless use of cat,
unuseful use of xargs
and I'm not sure if you really want the editcat $temp`` which is editing the file at the content of $temp

Bash script to sort JPEGs after pixelWidth

I'm trying to sort a folder on a Mac with hundreds of jpgs into separate folders
after their pixelWidth with /usr/bin/sips. When I run the script it shows an
Error 4: no file was specified. The variable $f is empty in the first line?
I thought the "f" in for f in *jpg referred to the file as it loops through the folder.
imgWid=$( /usr/bin/sips -g pixelWidth $f | sed -n 2p | cut -d":" -f2- )
for f in *jpg; do if [ "$1" == "$imgWid" ]; then; mv $f $dir1 2>/dev/null; fi; done
I would appreciate help on how I can fix this.
$() runs the command at the point specified. (So line 1), $f is only defined in the loop (line 3).
Maybe:
function determineImageWidth()
{
/usr/bin/sips -g pixelWidth $1 | sed -n 2p | cut -dj":" -f2-
}
for f in *.jpg
do
width=$(determineImageWidth $f)
if [ -n $width ]
then
mkdir -p $width
mv $f $width/
else
echo "Can't determine the width for $f"
fi
done
You didn't specify what $f is in the first line of your script. As far as I can see it is just specified within the for loop.
You might want to change $f to $1 in the first line, to use an argument given to your script.

Resources