I'm trying to run the convert command on some images to resize them.
find build_reports/functional_tests/results -name '*.png' | xargs -I {} sh -c 'convert -resize 20% {} {}'
The problem that I have is that the files have ( and ) in their names (e.g. build_reports/functional_tests/results/Attachments/Screenshot of main screen (ID 1)_1_0FEF8183-AF87-4517-928D-8C4A2ED984D0.png) and I cannot rename these files because their linked somewhere else.
When I run the command I get the following warnings and the images are not resized
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `convert -resize 20% build_reports/functional_tests/results/Attachments/Screenshot of main screen (ID 1)_1_D94BAEBC-F463-4EEE-8FAE-C49AFF4A8FFE.png {}'
Is there anyway to get rid of these warning and make this work by somehow escaping the result of the find command?
Give a try to this:
find . -iname "*.png" -exec convert -resize 20% '{}' '{}' \;
Notice the single quotes'{}'
Related
I am running the following bash script to find and execute an ID3 modification command on all the .mp3 files in my folders
find -name "*.mp3" -exec bash -c 'eyeD3 --to-v1.1 "{}"' \;
It fails on filenames that contain dollar signs and backticks
bash: -c: line 0: unexpected EOF while looking for matching ``'
bash: -c: line 1: syntax error: unexpected end of file
filenames that fail are eg.
08 - Sam Smith - I'm Not The Only One (Feat. A$AP Rocky).mp3
02 - The Vaccines - Wreckin` Bar (Ra Ra Ra).mp3
I know these are special characters so need escaping - but how?
You don't need Bash there.
find -name '*.mp3' -exec eyeD3 --to-v1.1 {} +
Most probably you have some characters in file that change character of your command/parameters. Might be that your filename is not recognized as you thought it would be. Remeber: in linux shell problems with spces/special characters never end.
Therefore it would be easier to do it in safer way:
find -name "*.mp3" -print0 | xargs -n 1 -0 eyeD3 --to-v1.1
Have images in subfolders that need to be limited in size (720 max width or 1100 max height). Their filenames must be preserved. Started with:
for img in *.jpg; do filename=${img%.*}; convert -resize 720x1100\> "$filename.jpg" "$filename.jpg"; done
which works within each directory, but have a lot of subfolders with these images. Tried find . -iname "*.jpg" -exec cat {} but it did not create a list as expected.
This also didn't work:
grep *.jpg | while read line ; do `for img in *.jpg; do filename=${img%.jpg}; convert -resize 720x1100\> "$filename.jpg" "$filename.jpg"`; done
Neither did this:
find . -iname '*jpg' -print0 | while IFS= read -r -d $'\0' line; do convert -resize 720x1100\> $line; done
which gives me error message "convert: no images defined." And then:
find . -iname '*.jpg' -print0 | xargs -0 -I{} convert -resize 720x1100\> {}
gives me the same error message.
It seems you're looking for simply this:
find /path/to/dir -name '*.jpg' -exec mogrify -resize 720x1100\> {} \;
In your examples, you strip the .jpg extension, and then you add it back. No need to strip at all, and that simplifies things a lot.
Also, convert filename filename is really the same as mogrify filename. mogrify is part of ImageMagick, it's useful for modifying files in-place, overwriting the original file. convert is useful for creating new files, preserving originals.
Since all of the subdirectories are two levels down, found this worked:
for img in **/*/*.jpg ; do filename=${img%.*}; convert -resize 720x1100\> "$filename.jpg" "$filename.jpg"; done
Thanks to #pjh for getting me started. This also worked:
shopt -s globstar ; for img in */*/*.jpg ; do filename=${img%.*}; convert -resize 720x1100\> "$filename.jpg" "$filename.jpg"; done
But I got the error message "-bash: shopt: globstar: invalid shell option name" but all of the images larger than specified were resized with filenames preserved.
I can convert an image like this:
convert -resize 50% foo.jpg foo_50.jpg
How can I automate such a command to convert all the images in a folder?
You can assume every image has .jpg extension.
A solution easily adaptable to automate the conversion of all the images inside the subdirectories of the working directory is preferable.
You can use a for loop with pattern expansion:
for img in */*.jpg ; do
convert -resize 50% "$img" "${img%.jpg}"_50.jpg
done
${variable%pattern} removes the pattern from the right side of the $variable.
You can use find -exec:
find -type f -name '*.jpg' -exec \
bash -c 'convert -resize 50% "$0" "${0%.jpg}"_50.jpg' {} \;
find -type f -name '*.jpg' finds all .jpg files (including those in subdirectories) and hands it to the command after -exec, where it can be referenced using {}.
Because we want to use parameter expansion, we can't use -exec convert -resize directly; we have to call bash -c and supply {} as a positional parameter to it ($0 inside the command). \; marks the end of the -exec command.
You can also try this (less elegant) one-liner using ls+awk:
ls *.jpg | awk -F '.' '{print "convert -resize 50% "$0" "$1"_50.jpg"}' | sh
this assumes that all the .jpg files are in the current directory. before running this, try to remove the | sh and see what is printed on the screen.
When I run this command in Terminal:
find . -type f -name "*.png" -exec sh -c "file {} | egrep -o '^.*\d+,'" \;
I get this error if a filename contains parentheses:
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `file ./(terrible filename).png | egrep -o '^.*\d+,''
I know it has something to do with the sh -c, but I don't know how to fix it, thanks.
./(terrible filename).png: PNG image data, 512 x 512,
// trying to get this result
You are basically pasting the file name into sh -c '...' without any quoting. The string inside sh -c after the substitutions made by find needs to be valid sh syntax, which means there can be no unquoted single quotes, parentheses, etc.
A more robust approach is to use -exec file {} and pass all the output from find to egrep.
find . -type f -name "*.png" -exec file {} \; | egrep -o '^.*\d+,'
The placeholder token {} gets replaced by find with the filename currently being processed. When it is a lone token, find can pass in any file name at all; but if you interpolate it into a longer string, such as a shell command, you will need to ensure that any necessary quoting etc. is added somehow. That's messy, so usually you will want to find a solution where you don't need to do that.
(As pointed out in comments to the other answer, -exec sh -c 'file "$1"' _ {} \; is another way to accomplish that; this generalizes to arbitrarily complex shell commands. If your find supports exec {} \+ you want to add a simple loop: -exec sh 'for f; do file "$f"; done' _ {} \+ -- incidentally, the _ is a dummy placeholder for $0.)
Are there parentheses in the file names? This might help:
find . -type f -name "*.png" -exec sh -c "file '{}' | egrep -o '^.*\d+,'" \;
I am trying to use the following command to find all PDFs in the current directory (not recursively) - however I don't think it likes the '{}' on the --out.
find . -iname "*.pdf" -maxdepth 1 -exec sips -s format jpeg --resampleHeightWidth 129 100 '{}' --out '{}'.jpg \;
The find work when used with -print and sips works when I specify the name --out test.jpg. Any way to make this work? Or should I try xargs? I don't really want to use a loop for simplicity... Any ideas?
UPDATE:
I attempted using xargs - but again get an error out_dir_not_found.
find . -iname "*.pdf" -maxdepth 1 -print0 | xargs -0 -I % sips -s format jpeg --resampleHeightWidth 129 100 % --out "%.jpg"
mymbpro:pdfs dh$ find . -iname "*.pdf" -maxdepth 1 -print0 | xargs -0 -I % sips -s format jpeg --resampleHeightWidth 129 100 % --out "%.jpg"
Error 10: out_dir_not_found /Users/darenhunter/Desktop/pdfs/ATTENTION.pdf.jpg
Try 'sips --help' for help using this tool
Error 10: out_dir_not_found /Users/darenhunter/Desktop/pdfs/DisNCLB119.pdf.jpg
Try 'sips --help' for help using this tool
Error 10: out_dir_not_found /Users/darenhunter/Desktop/pdfs/services2012.pdf.jpg
Try 'sips --help' for help using this tool
Error 10: out_dir_not_found /Users/darenhunter/Desktop/pdfs/Fall2011.pdf.jpg
Try 'sips --help' for help using this tool
If you will be executing over many results, it is more efficient to pipe the
results to the xargs command instead. xargs is a more modern
implementation, and handles long lists in a more intelligent way. The
print0 option can be used with this.
The following command will ensure that filenames with whitespaces are passed
to the executed COMMAND without being split up by the shell. It looks
complicated at first glance, but is widely used.
find . -print0 | xargs -0 COMMAND
ref