Not sure how to ask a question about a previous posted question so if I should just add to the previous question somehow feel free to tell me.
Anyway, I posted a question yesterday
shell script to change .pdf files to .png Mac OS 10.3
sips does work and if I do it on the command line one file at a time it works but my for loop isn't working
heres what I got
for pdf in *{pdf,PDF} ; do
sips -s format png --out "${pdf%%.*}.png" "$pdf"
done
and its saying
Warning: *{pdf, not a valid file - skipping
Error 4: no file was specified
Try 'sips --help' for help using this tool
thanks
Looks fine to me. Are you sure you are using bash to execute this script and not /bin/sh?
Make sure your first line is:
#! /bin/bash
Try echoing the files and see if it works:
for pdf in *{pdf,PDF} ; do
echo "$pdf"
done
If your shell is bash you can do this
shopt -s nullglob
This changes the behavior of bash when no globs match. Normally if you say *pdf and there are no files ending in "pdf" it will return a literal asterisk instead. Setting nullglob makes bash do what you would expect and return nothing in such a case.
Alternately, and more robustly, you could do it this way
for pdf in *[pP][dD][fF] ; do
sips -s format png --out "${pdf%%.*}.png" "$pdf"
done
Which should work without nullglob being set and in all shells that support parameter substitution with this syntax. Note that this is still not robust on case sensitive filesystems due to a risk of name collision if you have two PDF files whose names differ only due to the case of the extension. To handle this case properly you could do
for pdf in *[pP][dD][fF] ; do
sips -s format png --out "${pdf%%.*}.$(tr pPdDfF pPnNgG <<<"${pdf#*.}")" "$pdf"
done
This should be sufficiently robust.
EDIT: Updated to correct incorrect $pdf expansion in the extension.
UPDATED2
#!/bin/bash
# Patters patching no files are expanded into null string
# this will allow us to make this script work when no files
# exist in this directory with this extension
shopt -s nullglob
# Consider only the lowercase 'pdf' extensions and make them lowercase 'png'
for b in *.pdf
do
c="$b"
b="${b/.pdf/}"
convert"$c" "$b.png"
done
# Consider only the uppercase 'pdf' extensions and make them uppercase 'png'
for b in *.PDF
do
c="$b"
b="${b/.PDF/}"
convert "$c" "$b.PNG"
done
Note that the convert program is a part of the ImageMagick program.
Related
I'm trying to create an Automator service that converts a MTS file to MP4 from the macOS Finder. To do so I need to setup a little bash script, but I don't know how to use input filename (for example, "file.MTS") and then generate a file called "file.mp4" with HandBrakeCLI.
I'm doing something wrong when I'm trying to assign the filename without the extension to a variable and then using it, but I don't know what is the problem:
for if in "$#"
do
dest=`"$(basename "$if" | sed 's/\(.*\)\..*/\1/')"`
/Applications/HandBrakeCLI -i "$if" -o "$dest".mp4 --preset="Fast 1080p30"
done
You don't need sed; basename already knows how to strip a given extension.
for if in "$#"; do
dest=$(basename "$if" .MTS).mp4
/Applications/HandBrakeCLI -i "$if" -o "$dest" --preset="Fast 1080p30"
done
As mentioned in a comment, the backticks are unnecessary and incorrect.
For example,
$ basename /path/to/foo.txt .txt
foo
If you don't know the actual extension ahead of time, parameter expansion is sufficient.
dest=$(basename "$if")
dest=${dest%.*} # Strip at most one extension
or
dest=${dest%%.*} # Strip *all* extensions
I have the following code below, which is an attempt to create a symbolic link for each file matching the pattern *let.txt in the working folder, which has the same name as the original file but with underscores instead of spaces. I need to keep the original files untouched hence the use of symlinks.
The error I get is
ln: failed to access ‘*let.txt’: Too many levels of symbolic links
So I see the search string is getting passed very literally into tempstring, I don't know why. How do I correct my code?
for file in *let.txt; do
tempstring="${file// /_}"
ln -s "$file" $tempstring
done
Try putting quotes around all your variables when 1 variable is 1 parameter:
for file in *let.txt; do
tempstring="${file// /_}"
ln -s "$file" "$tempstring"
done
Tested and works on GNU bash, version 5.0.11(1)-release (x86_64-apple-darwin18.6.0)
This code just seems to replace the first file, not append file1.pdf to it.
I need the file to append not replace.
#!/bin/bash
FILES=("/Users/a/folder/"*.pdf)
for f in "${FILES[#]}"
do
echo "${f}"
"/System/Library/Automator/Combine PDF Pages.action/Contents/Resources/join.py" -o "${f}" "${f}" "/Users/a/folder2/file1.pdf"
done
I noticed, if I run the code manually, but use a different name for the first and second parameters, it seems to work. However, I do not know how to change the name of the first parameter without making it a constant.
It seems to me your problem has nothing to do with Ruby. As I'm understanding it, you are trying to use the command line on MacOS X El Capitan to merge a PDF file with other PDF files.
If I understood your problem correctly, then you probably should heed the advice of this weblog and use the command "/System/Library/Automator/Combine PDF Pages.action/Contents/Resources/join.py" which is available from MacOS X Tiger onwards.
Note that if the file you want to append is in the same directory where all the files are you want to append to, you'll run into problems: the script join.py does not seem to appreciate being given the same file thrice, so place your file elsewhere (the one you want to append to all files).
Try something along the lines of:
#!/bin/bash
for f in /Absolute/Path/To/The/PDFS/*.pdf;
do /System/Library/Automator/Combine\ PDF\ Pages.action/Contents/Resources/join.py -o $f $f /Absolute/Path/To/The/File/To/Append; done
Solution:
#!/bin/bash
FILES=("/Users/a/folder/"*.pdf)
for f in "${FILES[#]}"
do
echo "${f}"
a="${f%.pdf}"
"/System/Library/Automator/Combine PDF Pages.action/Contents/Resources/join.py" -o "${a}_x.pdf" "${f}" "/Users/a/folder2/file1.pdf"
done
Hi I have a file that sorts some code and reformats it. I have over 200 files to apply this to with incremental names run001, run002 etc. Is there a quick way to write a shell script to execute this file over all the files? The executable creates a new file called run001an etc so just running over all files containing run doesnt work, how do i increment the file number?
Cheers
how about:
for i in ./run*; do
process_the_file $i
done
which is valid Bash/Ksh
To be more specific with run### files you can have
for file in dir/run[0-9][0-9][0-9]; do
do_something "$file"
done
dir could simply be just . or other directories. If they have spaces, quote them around "" but only the directory parts.
In bash, you can make use of extended patterns to generate all number matches not just 3 digits:
shopt -s extglob
for file in dir/run+([0-9]); do
do_something "$file"
done
I am very new with linux usage maybe this is my first time so i hope some detailed help please.
I have more than 500 files in multiple directories on my server (Linux) I want to change their extensions to .xml using bash script
I used a lot of codes but none of them work some codes i used :
for file in *.txt
do
mv ${file} ${file/.txt}/.xml
done
or
for file in *.*
do
mv ${file} ${file/.*}/.xml
done
i do not know even if the second one is valid code or not i tried to change the txt extension beacuse the prompt said no such file '.txt'
I hope some good help for that thank you
Explanation
For recursivity you need Bash >=4 and to enable ** (i.e. globstar) ;
First, I use parameter expansion to remove the string .txt, which must be anchored at the end of the filename (%) :
the # anchors the pattern (plain word or glob) to the beginning,
and the % anchors it to the end.
Then I append the new extension .xml
Be extra cautious with filename, you should always quote parameters expansion.
Code
This should do it in Bash (note that I only echothe old/new filename, to actually rename the files, use mv instead of echo) :
shopt -s globstar # enable ** globstar/recursivity
for i in **/*.txt; do
[[ -d "$i" ]] && continue; # skip directories
echo "$i" "${i/%.txt}.xml";
done
If its a matter of a one or two sub-directories, you can use the rename command:
rename .txt .xml *.txt
This will rename all the .txt to .xml files in the directory from which the command is executed.
If all the files are in same directory, it can be done using a single command. For example you want to convert all jpg files to png, go to the related directory location and then use command
rename .jpg .png *
I wanted to rename "file.txt" to "file.jpg.txt", used rename easy peezy:
rename 's/.txt$/.jpg.txt/' *.txt
man rename will tell you everything you need to know.
Got to love Linux, there's a tool for everything :-)
passing command line argument for dir path
#!/bin/sh
cd $1
names_1=`ls`
for file in ${names_1}
do
mv ${file} ${file}.jpg
done