bash find where starting directory has a space - bash

MacOSX Bash terminal:
find . -type f
is straightforward
find A -type f
where A is a directory is equally straightforward
However I have a directory
A\ copy
(on the system it looks like
A copy of course)
I want to search this as the starting directory, ideally using a string variable for convenience. Find cannot deal with the space in the directory name... I have tried
temp="A\ copy" ; find "$temp" -type f
temp="A copy" ; find "$temp" -type f
temp="A copy" ; find \""$temp"\" -type f
and pretty much every other combination in that set you can think of. What am I doing wrong? Grateful for assistance and apologies if its a newbie question but I did try to look everywhere on this one.
This is the full code so you can see what I am trying to do
function find_missing_files_two_input_directories () {
if [[ -z "$1" ]] || [[ -z "$2" ]]; then echo "enter directory" ;
else
firstDirectory=$(absolutePath "$1")
secondDirectory=$(absolutePath "$2")
gfind "$firstDirectory" -type f -printf "%f\n" | sort > /tmp/compare_directory_1
gfind "$secondDirectory" -type f -printf "%f\n" | sort > /tmp/compare_directory_2
diff /tmp/compare_directory_1 /tmp/compare_directory_2 | grep -e ">" -e "<" | tee /tmp/tmp_compare_output
cat /tmp/tmp_compare_output | sed 's/<//' | sed 's/>//' > /tmp/compare_output
mkdir -p /tmp/compare_validation_copies
while IFS= read -r line ; do \
echo "$line"
gfind "$firstDirectory" -type f -name "$line"
#gfind "$firstDirectory" -type f -name "$line" -print -exec \gcp --backup="t" "{}" /tmp/compare_validation_copies
gfind "$secondDirectory" -type f -name "$line"
#gfind "$secondDirectory" -type f -name "$line" -print -exec \gcp --backup="t" "{}" /tmp/compare_validation_copies
done < /tmp/compare_output
\rm /tmp/compare_directory_1 /tmp/compare_directory_2
#open /tmp/compare_validation_copies
#open -a Terminal /tmp/compare_validation_copies
fi
}

function find_missing_files_two_input_directories () {
if [[ -z "$1" ]] || [[ -z "$2" ]]; then echo "enter directory" ;
else
firstDirectory=$(absolutePath "$1")
secondDirectory=$(absolutePath "$2")
gfind "$firstDirectory" -type f -printf "%f\n" | sort > /tmp/compare_directory_1
gfind "$secondDirectory" -type f -printf "%f\n" | sort > /tmp/compare_directory_2
diff /tmp/compare_directory_1 /tmp/compare_directory_2 | grep -e ">" -e "<" | tee /tmp/tmp_compare_output
echo "next bit"
cat /tmp/tmp_compare_output | sed 's/<//' | sed 's/>//' > /tmp/compare_output
mkdir -p /tmp/compare_validation_copies
while IFS= read -r line ; do \
gfind "$firstDirectory" -type f -name $line -exec \gcp --backup="t" "{}" /tmp/compare_validation_copies \;
gfind "$secondDirectory" -type f -name $line -exec \gcp --backup="t" "{}" /tmp/compare_validation_copies \;
done < /tmp/compare_output
\rm /tmp/compare_directory_1 /tmp/compare_directory_2
open /tmp/compare_validation_copies
open -a Terminal /tmp/compare_validation_copies
fi
}

Related

traverse through folder and do something with specific file types

I'm working on a bash script that should go through a directory and print all files and if it hits a folder it should call it's self and do it again. I believe my problem lies with if [[ $file =~ \.yml?yaml$ ]]; when I remove the tilda it runs but not correctly if [[ $file = \.yml?yaml$ ]];
It returns "this a file isn't need -> $file" even though it's a yaml.
#!/bin/bash
print_files_and_dirs() {
for file in $1/*;
do
if [ -f "$file" ];
then
if [[ $file =~ \.yml?yaml$ ]];
then
echo "this is a yaml file! -> $file"
else
echo "this a file isn't need -> $file"
fi
else
print_files_and_dirs $file
fi
done
}
print_files_and_dirs .
Maybe you can use find to find the yaml files and do something with them.
find "$PWD" \
-type f \( -name "*.yaml" -or -name "*.yml" \) \
-exec echo found {} \;
If you only want the file name without the path, you could use printf to get the names and pipe it to xargs.
find "$PWD" \
-type f \( -name "*.yaml" -or -name "*.yml" \) \
-printf '%f\n' \
| xargs -I{} echo found {}

Bash - file path can not be read for LAME encoder

How do I properly escape the path to come out of find to a new command argument?
#!/bin/bash
for f in $(find . -type f -name '*.flac')
do
if flac -cd "$f" | lame -bh 320 - "${f%.*}".mp3; then
rm -f "$f"
echo "removed $f"
fi
done
returns
lame: excess arg Island of the Gods - 3.mp3
Using a Bash for loop is not ideal for the results of find or ls. There are other ways to do it.
You may want to use -print0 and xargs to avoid word splitting issues.
$ find [path] -type f -name *.flac -print0 | xargs -0 [command line {xargs puts in fn}]
Or use -exec primary in find:
$ find [path] -type f -name *.flac -exec [process {find puts in fn}] \;
Alternative, you can use a while loop:
find [path] -type f -name *.flac | while IFS= read -r fn; do # fn not quoted here...
echo "$fn" # QUOTE fn here!
# body of your loop
done

Bash Script interactive mv issues

I'm working on a bash script to help organize files and I want to use mv -i to make sure I don't write over something important.
The script is working right now except for the -i for the mv.
It shows (y/n [n]) not overwritten part, but then goes and and doesn't allow me to interact with it.
createList()
{
ls *.epub | sed 's/-.*//' |uniq >> list.txt
ls *.mobi | sed 's/-.*//' |uniq >> list2.txt
}
atag()
{
find /Users/j/Desktop/Source -maxdepth 1 -iname "*.epub" -type f -print0 | xargs -0 -I '{}' tag -a Purple {}
find /Users/j/Desktop/Source -maxdepth 1 -iname "*.mobi" -type f -print0 | xargs -0 -I '{}' tag -a Purple {}
}
moveEpub()
{
while read -r line; do
if [ -d "/Users/j/Desktop/Dest/$line" ]; then
if [ -d "/Users/j/Desktop/Dest/$line/EPUB" ]; then
find /Users/j/Desktop/Source/ -maxdepth 1 -iname "*$line*" -and ! -iname ".*$line*" -type f -print0 | xargs -0 -I '{}' mv -i {} /Users/j/Desktop/Dest/"$line"/EPUB/
else
mkdir "/Users/j/Desktop/Dest/$line/EPUB"
find /Users/j/Desktop/Source/ -maxdepth 1 -iname "*$line*" -and ! -iname ".*$line*" -type f -print0 | xargs -0 -I '{}' mv -i {} /Users/j/Desktop/Dest/"$line"/EPUB/
fi
fi
done < "list.txt"
}
moveMobi()
{
while read -r line; do
if [ -d "/Users/j/Desktop/Dest/$line" ]; then
if [ -d "/Users/j/Desktop/Dest/$line/MOBI" ]; then
find /Users/j/Desktop/Source/ -maxdepth 1 -iname "*$line*" -and ! -iname ".*$line*" -type f -print0 | xargs -0 -I '{}' mv -i {} /Users/j/Desktop/Dest/"$line"/MOBI/
else
mkdir "/Users/j/Desktop/Dest/$line/MOBI"
find /Users/j/Desktop/Source/ -maxdepth 1 -iname "*$line*" -and ! -iname ".*$line*" -type f -print0 | xargs -0 -I '{}' mv --interactive {} /Users/j/Desktop/Dest/"$line"/MOBI/
fi
fi
done < "list2.txt"
}
clear
createList
atag
moveEpub
moveMobi
rm list.txt
rm list2.txt
If you want mv -i to interact with the terminal, that means its stdin needs to be attached to that terminal. There are several places, here, where you're overriding stdin.
For instance:
# THIS LOOP OVERRIDES STDIN
while read -r line
...
done <list.txt
...redirects stdin for the entire duration of the loop, so instead of reading from the user, mv reads from list.txt. To change this, use a different file descriptor:
# This loop uses FD 3 for stdin
while read -r line <&3
...
done 3<list.txt
Another place is in calling xargs. Instead of:
# Overrides stdin for xargs and mv to contain output from find
find ... -print0 | xargs -0 -I '{}' mv -i '{}' "$dest"
...use:
# directly executes mv from find, stdin not modified
find ... -exec mv -i '{}' "$dest" ';'
That said, I would suggest ditching list.txt and list2.txt altogether; you simply don't need them; for that matter, you don't need find either.
dest=/Users/j/Desktop/Dest
source=/Users/j/Desktop/Source
moveEpub() {
local -A finished=( ) # WARNING: This requires bash 4.0 or newer.
for name in *.epub; do
prefix=${name%%-*} # remove everything past the first dash
[[ ${finished[$prefix]} ]] && continue # skip if already done with this prefix
finished[$prefix]=1 # set flag to skip other files w/ this prefix
[[ -d $dest/$prefix ]] || continue # skip if no directory exists for this prefix
mkdir -p "$dest/$prefix/EPUB" # create destination if not existing
mv -i "$source"/*"$prefix"* "$dest/$prefix/EPUB"
done
}
You can use built in find action -exec instead of piping to xargs :
find /Users/j/Desktop/Source/ -maxdepth 1 \
-iname "*$line*" -and ! -iname ".*$line*" -type f \
-exec mv -i {} /Users/j/Desktop/Dest/"$line"/EPUB/ \;

Find commands don't work in script only

I have a script that searches specific locations for .txt files and outputs the results to stdout, and to a file using the tee command. At least it's supposed to. I'm having some strange issues with it however. Here's the code:
echo -e "${HIGHLIGHT}Sensitive files:${OFF}"
echo "## Sensitive files:" >> $ofile
for file in $(cat $1); do ls -lh $file 2>/dev/null; done | tee -a $ofile
echo " " | tee -a $ofile
echo -e "${HIGHLIGHT}Suids:${OFF}"
echo "## Suids:" >> $ofile
find / -type f \( -perm -04000 -o -perm -02000 \) -exec ls -Alh {} \; 2>/dev/null | tee -a $ofile
echo " " | tee -a $ofile
echo -e "${HIGHLIGHT}Owned by root only:${OFF}"
echo "## Owned by root only:" >> $ofile
find / -type f -user root \( -perm -04000 -o -perm -02000 \) -exec ls -lg {} \; 2>/dev/null | tee -a $ofile
echo " " | tee -a $ofile
# Text files
echo -e "${HIGHLIGHT}Text files:${OFF}"
echo "## Text files:" >> $ofile
find /etc -type f -name *.txt -exec ls -lh {} \; 2>/dev/null | tee -a $ofile
find /home -type f -name *.txt -exec ls -lh {} \; 2>/dev/null | tee -a $ofile
find /root -type f -name *.txt -exec ls -lh {} \; 2>/dev/null | tee -a $ofile
The strange thing is that all of the commands work just fine, except for the find searches for .txt files at the bottom. None of those commands work in the script, yet if I copy and paste them into the terminal and run it exactly as they were in the script, they work just fine. How is this even possible?
You need to quote or escape the * in your -name patterns, otherwise the shell tries to expand it and use the expanded form in its place in the command line.
find /etc -type f -name '*.txt' -exec ls -lh {} \; 2>/dev/null | tee -a $ofile
and the others being similar will work

HandBrakeCLI command break while loop?

In a bash script, result of find is
/path/to/file1.nrg
/path/to/file2.nrg
/path/to/file3.nrg
i have this while loop:
process preset
processpreset ()
{
x=$1
# Replace , by -o -iname for file types.
iname=" -o -iname \*."
# Find specified files. Eval allow var prst1_in with find.
eval "find "$fpath" -type f \( -iname \*."${prst_in[x]//,/$iname}" \) -size ${prst_lim_size[x]}" | sort | while read -r i
do
titles=$(HandBrakeCLI --input "$i" --scan |& grep -Po '(?<=DVD has )([0-9]+)')
if (( $titles > 1 )); then
echo "DVD has $titles title(s)"
fi
done
}
the script only echo 1 time File has 8 title(s) after it stop, when using titles="8" the loop echo for all files in folder. Can anyone point me my error please?
EDIT: what work for me, many thanks Anubhava
processpreset ()
{
x=$1
# Replace , by -o -iname for file types.
iname=" -o -iname \*."
# Find specified files. Eval allow var prst1_in with find.
eval "find "$fpath" -type f \( -iname \*."${prst_in[x]//,/$iname}" \) -size ${prst_lim_size[x]}" | sort | while read -r i
do
titles="$(echo ""|HandBrakeCLI --input "$i" --scan |& grep -Po '(?<=DVD has )([0-9]+)')"
if (( $titles > 1 )); then
echo "DVD has $titles title(s)"
fi
done
}
the echo ""| fix the problem.
ok try this script:
while read -r i
do
echo "i is: $i"
titles="$(echo ""|HandBrakeCLI --input "$i" --scan | grep -Po '(?<=DVD has )([0-9]+)')"
if (( titles > 1 )); then
echo "DVD has $titles title(s)"
fi
done < <(find "$imgpath" -type f \( -iname \*.iso -o -iname \*.nrg -o -iname \*.img \) | sort)

Resources