I'm tryin to add a text comment (not a note) to a pdf file.
I create a date.ps file with contains the text comment :
%!
/Arial findfont
30 scalefont
setfont
newpath
10 720 moveto
(PAID on 5.1.2013) show
showpage
and I launch the shell command with $i=name of the pdf file to tag:
gs -q -dNOPAUSE -dSAFER -dBATCH -sOutputFile=$RFP/$DOMAINE/$NEWNAME -sDEVICE=pdfwrite -sPAPERSIZE=a4 date.ps $i
This works, but it create a new 1st page empty with the text "PAID on 5.1.2013" alone.
I do not find the trick to overlay the text on the 1st page of the original pdf.
Can you help me pls
You can do this directly to the PDF using the free cpdf command line tools:
For example,
cpdf -add-text "PAID on 5.1.2013" -topleft 100 -font "Helvetica" -font-size 30 in.pdf -o out.pdf
Since cpdf has a strange license for commercial use, I tried to find an alternative. Here is one (you need to install enscript, ps2pdf and (pdftk or qpdf)). The idea is just to use enscript to create a .ps from a text, then you convert this .ps into a .pdf using ps2pdf, and then you stack it on top of the original pdf with pdftk or qpdf...).
pdtfk version:
echo "I will be stamped on top of the page" | \
enscript -B -f Courier-Bold16 -o- | \
ps2pdf - | \
pdftk input.pdf stamp - output output.pdf
qpdf version:
If you want the text to repeat on all pages:
tmpfile=$(mktemp) && echo "I will be stamped on top of the page" | \
enscript -B -f Courier-Bold16 -o- | \
ps2pdf - "$tmpfile" && qpdf input.pdf --overlay "$tmpfile" --repeat=1-z -- output.pdf
if you just want to put it on the first page:
tmpfile=$(mktemp) && echo "I will be stamped on top of the page" | \
enscript -B -f Courier-Bold16 -o- | \
ps2pdf - "$tmpfile" && qpdf input.pdf --overlay "$tmpfile" -- output.pdf
See the enscript documentation for more options on how to format the text.
NB: mktemp is just used to create a temporary file to provide a one-liner solution, since qpdf does not accept input from stdin. Remove the tmpfile with rm "$tmpfile" after the command is done.
Because your PostScript executed a showpage it ejects the first page after marking it, so the remaining content is therefore on the 2nd and subsequent pages. If you don;t execute showpage then the marks you make will be on the first page, and the first PDF page will be drawn 'on top' of it.
More complex code can use BeginPage and EndPage to draw over and under the page contents, and to do so on specified pages, among other things.
[added later]
Try this:
%!
<<
/EndPage
{
0 eq
{
0 eq
{
/Arialabold findfont 22 scalefont setfont newpath 250 820 moveto 1 0 0 setrgbcolor (PAYE PAR CCP LE $DATEPMT) show
} if
true
}
{
pop false
} ifelse
} >> setpagedevice
Works for me.
Related
youtube-dl can take some time parsing remote sites when called multiple times.
EDIT0 : I want to fetch multiple properties (here fileNames and remoteFileSizes) output by youtube-dl without having to run it multiple times.
I use those 2 properties to compare the local file size and ${remoteFileSizes[$i]} to tell if the file is finished downloading.
$ youtube-dl --restrict-filenames -o "%(title)s__%(format_id)s__%(id)s.%(ext)s" -f m4a,18,webm,251 -s -j https://www.youtube.com/watch?v=UnZbjvyzteo 2>errors_youtube-dl.log | jq -r ._filename,.filesize | paste - - > input_data.txt
$ cat input_data.txt
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__18__UnZbjvyzteo__youtube_com.mp4 8419513
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__250__UnZbjvyzteo__youtube_com.webm 1528955
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__140__UnZbjvyzteo__youtube_com.m4a 2797366
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__244__UnZbjvyzteo__youtube_com.webm 8171725
I want the first column in the fileNames array and the second column in the remoteFileSizes.
For the time being, I use a while read loop, but when this loop is finished my two arrays are lost :
$ fileNames=()
$ remoteFileSizes=()
$ cat input_data.txt | while read fileName remoteFileSize; do \
fileNames+=($fileName); \
remoteFileSizes+=($remoteFileSize); \
done
$ for fileNames in "${fileNames[#]}"; do \
echo PROCESSING....; \
done
$ echo "=> fileNames[0] = ${fileNames[0]}"
=> fileNames[0] =
$ echo "=> remoteFileSizes[0] = ${remoteFileSizes[0]}"
=> remoteFileSizes[0] =
$
Is it possible to assign two bash arrays with a single command ?
You assign variables in a subshell, so they are not visible in the parent shell. Read https://mywiki.wooledge.org/BashFAQ/024 . Remove the cat and do a redirection to solve your problem.
while IFS=$'\t' read -r fileName remoteFileSize; do
fileNames+=("$fileName")
remoteFileSizes+=("$remoteFileSize")
done < input_data.txt
You might also interest yourself in https://mywiki.wooledge.org/BashFAQ/001.
For what it's worth, if you're looking for specific/bespoke functionality from youtube-dl, I recommend creating your own python scripts using the 'embedded' approach: https://github.com/ytdl-org/youtube-dl/blob/master/README.md#embedding-youtube-dl
You can set your own signal for when a download is finished (text/chime/mail/whatever) and track downloads without having to compare file sizes.
I have a number of project folders that all got their date modified set to the current date & time somehow, despite not having touched anything in the folders. I'm looking for a way to use either a batch applet or some other utility that will allow me to drop a folder/folders on it and have their date modified set to the date modified of the most recently modified file in the folder. Can anyone please tell me how I can do this?
In case it matters, I'm on OS X Mavericks 10.9.5. Thanks!
If you start a Terminal, and use stat you can get the modification times of all the files and their corresponding names, separated by a colon as follows:
stat -f "%m:%N" *
Sample Output
1476985161:1.png
1476985168:2.png
1476985178:3.png
1476985188:4.png
...
1476728459:Alpha.png
1476728459:AlphaEdges.png
You can now sort that and take the first line, and remove the timestamp so you have the name of the newest file:
stat -f "%m:%N" *png | sort -rn | head -1 | cut -f2 -d:
Sample Output
result.png
Now, you can put that in a variable, and use touch to set the modification times of all the other files to match its modification time:
newest=$(stat -f "%m:%N" *png | sort -rn | head -1 | cut -f2 -d:)
touch -r "$newest" *
So, if you wanted to be able to do that for any given directory name, you could make a little script in your HOME directory called setMod like this:
#!/bin/bash
# Check that exactly one parameter has been specified - the directory
if [ $# -eq 1 ]; then
# Go to that directory or give up and die
cd "$1" || exit 1
# Get name of newest file
newest=$(stat -f "%m:%N" * | sort -rn | head -1 | cut -f2 -d:)
# Set modification times of all other files to match
touch -r "$newest" *
fi
Then make that executable, just necessary one time, with:
chmod +x $HOME/setMod
Now, you can set the modification times of all files in /tmp/freddyFrog like this:
$HOME/setMod /tmp/freddyFrog
Or, if you prefer, you can call that from Applescript with a:
do shell script "$HOME/setMod " & nameOfDirectory
The nameOfDirectory will need to look Unix-y (like /Users/mark/tmp) rather than Apple-y (like Macintosh HD:Users:mark:tmp).
I am trying to make a simple bash script which prints out the path of current song in MPD.
while [ 1 ]
do
mpc idle
track=$(mpc current | awk -F " - " '{print $2}')
echo $track
path_to_track=$(mpc search title "$track")
echo $path_to_track
"$path_to_track" >> /home/noob/MPDPlaylist/testplaylist.m3u
done
Now, the problem is as soon as my script tries to appenf the value of path_to_track to the file it generates the below error
player
Skin To Bone
Linkin Park/Living Things(2012)/09 - Linkin Park - Skin To Bone.mp3
test.sh: line 8: Linkin Park/Living Things(2012)/09 - Linkin Park - Skin To Bone.mp3: No such file or directory
Now, what am I doing wrong here. As you can see in the above code I already tried adding double quotes .
Right now you're trying to execute your mp3 files. You probably wanted to echo that:
echo "$path_to_track" >> /home/noob/MPDPlaylist/testplaylist.m3u
How can I append the following code to the end of numerous php files in a directory and its sub directory:
</div>
<div id="preloader" style="display:none;position: absolute;top: 90px;margin-left: 265px;">
<img src="ajax-loader.gif"/>
</div>
I have tried with:
echo "my text" >> *.php
But the terminal displays the error:
bash : *.php: ambiguous redirect
I usually use tee because I think it looks a little cleaner and it generally fits on one line.
echo "my text" | tee -a *.php
You don't specify the shell, you could try the foreach command. Under tcsh (and I'm sure a very similar version is available for bash) you can say something like interactively:
foreach i (*.php)
foreach> echo "my text" >> $i
foreach> end
$i will take on the name of each file each time through the loop.
As always, when doing operations on a large number of files, it's probably a good idea to test them in a small directory with sample files to make sure it works as expected.
Oops .. bash in error message (I'll tag your question with it). The equivalent loop would be
for i in *.php
do
echo "my text" >> $i
done
If you want to cover multiple directories below the one where you are you can specify
*/*.php
rather than *.php
BashFAQ/056 does a decent job of explaining why what you tried doesn't work. Have a look.
Since you're using bash (according to your error), the for command is your friend.
for filename in *.php; do
echo "text" >> "$filename"
done
If you'd like to pull "text" from a file, you could instead do this:
for filename in *.php; do
cat /path/to/sourcefile >> "$filename"
done
Now ... you might have files in subdirectories. If so, you could use the find command to find and process them:
find . -name "*.php" -type f -exec sh -c "cat /path/to/sourcefile >> {}" \;
The find command identifies what files using conditions like -name and -type, then the -exec command runs basically the same thing I showed you in the previous "for" loop. The final \; indicates to find that this is the end of arguments to the -exec option.
You can man find for lots more details about this.
The find command is portable and is generally recommended for this kind of activity especially if you want your solution to be portable to other systems. But since you're currently using bash, you may also be able to handle subdirectories using bash's globstar option:
shopt -s globstar
for filename in **/*.php; do
cat /path/to/sourcefile >> "$filename"
done
You can man bash and search for "globstar" for more details about this. This option requires bash version 4 or higher.
NOTE: You may have other problems with what you're doing. PHP scripts don't need to end with a ?>, so you might be adding HTML that the script will try to interpret as PHP code.
You can use sed combined with find. Assume your project tree is
/MyProject/
/MyProject/Page1/file.php
/MyProject/Page2/file.php
etc.
Save the code you want to append on /MyProject/. Call it append.txt
From /MyProject/ run:
find . -name "*.php" -print | xargs sed -i '$r append.txt'
Explain:
find does as it is, it looks for all .php, including subdirectories
xargs will pass (i.e. run) sed for all .php that have just been found
sed will do the appending. '$r append.txt' means go to the end of the file ($) and write (paste) whatever is in append.txt there. Don't forget -i otherwise it will just print out the appended file and not save it.
Source: http://www.grymoire.com/unix/Sed.html#uh-37
You can do (Work even if there's space in your file path) :
#!/bin/bash
# Create a tempory file named /tmp/end_of_my_php.txt
cat << EOF > /tmp/end_of_my_php.txt
</div>
<div id="preloader" style="display:none;position: absolute;top: 90px;margin-left: 265px;">
<img src="ajax-loader.gif"/>
</div>
EOF
find . -type f -name "*.php" | while read the_file
do
echo "Processing $the_file"
#cp "$the_file" "${the_file}.bak" # Uncomment if you want to save a backup of your file
cat /tmp/end_of_my_php.txt >> "$the_file"
done
echo
echo done
PS: You must run the script from the directory you want to browse
Inspired from #Dantastic answer :
echo "my text" | tee -a file1.txt | tee -a file2.txt
I have a directory full of small text files.
I want to create a new text file which has contents of all the small files (first have to convert the contents to lower case). Once, I have appended the small text files to get the larger one, I just want to sort it and only save unique elements.
cat directoryname/*|tr [:upper:] [:lower:] >filename.txt
sort -u filename.txt
or just:
cat directoryname/*|tr [:upper:] [:lower:]|sort -u > unique_elements.txt
Edit: i missed the part about the lowercase, see Kimvais' answer for the case transforming.
First, to append all the contents of files in /path/to/dir to 1 file:
find /path/to/dir -type f -maxdepth 1 -exec cat {} >> /var/tmp/large_file \;
Or:
cat /path/to/dir/*.log >> /var/tmp/fie_with_all_files_contents
Then to sort and only keep unique items:
sort -u /var/tmp/large_file -o /var/tmp/large_file
Or, with redirection:
sort -u /var/tmp/large_file > /var/tmp/sorted_file
man sort
man find