Passing a parameter containng space character inside a command inside bash function - linux

Problem Statement:
I require to compress pdfs of my internet bills for reimbursement. For this I use the following script.
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook -dNOPAUSE -dQUIET -dBATCH -sOutputFile=com_01-Jun-2022\ to\ 30-Jun-2022.pdf Downloads/InternetBills/01-Jun-2022\ to\ 30-Jun-2022.pdf
To make my life easier i created a bash function in bashrc which goes as follows
pdf_compress(){
mode=$1
in_file=$2
in_file_name=${in_file##*/}
out_file_name="compressed_${in_file_name}"
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/$mode -dNOPAUSE -dQUIET -dBATCH -sOutputFile=$out_file_name $2
}
Command run in the terminal
pdf_compress screen Downloads/InternetBills/01-Jun-2022\ to\ 30-Jun-2022.pdf
Output with Error
Error: /undefinedfilename in (to)
Operand stack:
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push
Dictionary stack:
--dict:731/1123(ro)(G)-- --dict:0/20(G)-- --dict:75/200(L)--
Current allocation mode is local
Last OS error: No such file or directory
GPL Ghostscript 9.50: Unrecoverable error, exit code 1
I can see that the spaces in filename is creating the issue. My confusion is while passing the parameter the entire relative path is taken as a single argument, but when used inside the bash function, it doesn't work. So how to use the path parameter which may contain spaces?
Any other approach which can solve this in bash is also appreciated.

You just need to use quotes around the path.

Related

Rotate jpeg images in ghostscript

I am converting .ps file to .jpeg file using ghostscript. But the output file should be rotated by 180 degree.
I am using the below command to rotate.
gswin64c.exe -sDEVICE=jpeg -dBATCH -dNOPAUSE -dSAFER -r300x300 -sOutputFile=E:\temp\test.jpg -dEPSCrop -c "<</Orientation 1>> setpagedevice" "E:\temp\myFile.ps.
Its giving below error:
GPL Ghostscript 9.10 (2013-08-30)
Copyright (C) 2013 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Error: /undefined in E:\temp\myFile.ps
Operand stack:
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-
2 %stopped_push --nostringval-- --nostringval-- --nostringval-- fa
lse 1 %stopped_push .runexec2 --nostringval-- --nostringval-- --nost
ringval-- 2 %stopped_push --nostringval--
Dictionary stack:
--dict:1182/1684(ro)(G)-- --dict:0/20(G)-- --dict:77/200(L)--
Current allocation mode is local
Last OS error: No such file or directory
GPL Ghostscript 9.10: Unrecoverable error, exit code 1
PS:- E:\temp\myFile.ps location and file exists in my system.
You have started arbitrary PostScript by using the -c switch. From then on everything until the next switch is treated as PostScript.
Your command line does not include any '-' between the closing " and the input filename, so the input filename is treated as part of the PostScript program. Since there is no PostScript token 'E;\temp\myFile.ps' the interpreter gives you an undefined error.
Try putting a -f (-f means treat the next thing as a filename) after the "...setpagedevice".
That said, I'm dubious this will achieve what you want anyway, it depends on what's in the input file. You've used -dEPSCrop yet the filename has a .ps extension. Unless the file is really an EPS then EPSCrop won't have any effect. If it is an EPS then the media size will be the dimensions of the EPS BoundingBox and (I believe) the Orientation will be ignored. If the input file is not an EPS then the EPSCrop will be ignored.
You are using a very elderly version of Ghostscript (7 years old) you should really update.

Running trinity for de novo assembly

I have a problem in running rnaseqtrinity, my command line is here:
/home/marziyeh/Software/trinityrnaseq-Trinity-v2.4.0/
Trinity --seqType fq --max_memory 4G --left /home/marziyeh/Data/RNA-seq\ data/Main\ data/paired_32_L3_1_trimmed.fq.gz paired_33_L3_1_
trimmed.fq.gz --right paired_32_L3_2_trimmed.fq.gz paired_33_L3_2_trimmed.fq.gz --CPU 2 --output trinity_out_dir_32_32.fq.gz
but the following error occours:
Error, cannot locate file: paired_33_L3_1_trimmed.fq.gz at /home/marziyeh/Software/trinityrnaseq-Trinity-v2.4.0/Trinity line
2429. main::create_full_path(ARRAY(0x555a78a86df0), 1) called at /home/marziyeh/Software/trinityrnaseq-Trinity-v2.4.0/Trinity line
1159
Thanks so much for your suggestions.
Look, your pramater of --left have a fatal error .
You command line indicates that your reads is paired end. But your path of left read have some problems.
1. Your should use \ to instead of /.
2. Your command shouldn't have the spaceļ¼Œ and the space in linux means a delimiter.

How to grep for a string pattern from command output in shell script?

I am compressing my pdf file using ghostscript which throws error on password protected case which I have to handle.
Shell script
GS_RES=`gs -sDEVICE=pdfwrite -sOutputFile=$gsoutputfile -dNOPAUSE -dBATCH $2 2>&1`
if [ "$GS_RES" != "" ]
then
gspassmsg="This file requires a password for access"
echo "Error message is :::::: "$GS_RES
gspassworddoc=`awk -v a="$GS_RES" -v b="$gspassmsg" 'BEGIN{print index(a,b)}'`
if [ $gspassworddoc -ne 0 ]
then
exit 3 #error code - password protected pdf
fi
fi
And my GS_RES value after executing the command is like the following
Error message 1:
GPL Ghostscript 9.19 (2016-03-23) Copyright (C) 2016 Artifex Software, Inc. All
rights reserved. This software comes with NO WARRANTY: see the file PUBLIC for d
etails. Error: /syntaxerror in -file- Operand stack: Execution stack: %interp_ex
it .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --n
ostringval-- --nostringval-- --nostringval-- false 1 %stopped_push 1967 1 3 %opa
rray_pop 1966 1 3 %oparray_pop 1950 1 3 %oparray_pop 1836 1 3 %oparray_pop --nos
tringval-- %errorexec_pop .runexec2 --nostringval-- --nostringval-- --nostringva
l-- 2 %stopped_push Dictionary stack: --dict:1196/1684(ro)(G)-- --dict:0/20(G)--
--dict:78/200(L)-- Current allocation mode is local Current file position is 1
Error message 2:
GPL Ghostscript 9.19 (2016-03-23) Copyright (C) 2016 Artifex Software, Inc. All rights reserved. This software comes with NO WARRANTY: see the file PUBLIC for details. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html Error: Cannot find a 'startxref' anywhere in the file. Output may be incorrect. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html Error: An error occurred while reading an XREF table. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html The file has been damaged. This may have been caused gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html by a problem while converting or transfering the file. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html Ghostscript will attempt to recover the data. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html However, the output may be incorrect. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html Error: Trailer dictionary not found. Output may be incorrect. No pages will be processed (FirstPage > LastPage). gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html This file had errors that were repaired or ignored. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html Please notify the author of the software that produced this gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html file that it does not conform to Adobe's published PDF gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html specification. gs.pdf gsempty.pdf new_sathishks_protected.html sathishks_protected.html The rendered output from this file may be incorrect.
On running awk on Error message 2
gspassmsg="This file requires a password for access"
gspassworddoc=`awk -v a="$GS_RES" -v b="$gspassmsg" 'BEGIN{print index(a,b)}'`
It throws me the following error
Error : awk: newline in string GPL Ghostscript 9.19... at source line 1
Error message 3
**** Error: Cannot find a 'startxref' anywhere in the file.
**** Warning: An error occurred while reading an XREF table.
**** The file has been damaged. This may have been caused
**** by a problem while converting or transfering the file.
**** Ghostscript will attempt to recover the data.
**** Error: Trailer is not found.
**** This file had errors that were repaired or ignored.
**** Please notify the author of the software that produced this
**** file that it does not conform to Adobe's published PDF
**** specification.
I couldn't capture this error with the snippet from the below answer
if ! gs_res=$(gs -sDEVICE=pdfwrite -sOutputFile="$gsoutputfile" -dNOPAUSE -dBATCH "$2" 2>&1 1>/dev/null); then
echo "Error message is :::::: $gs_res" >&2
gspassmsg='This file requires a password for access'
[[ $gs_res == *"$gspassmsg"* ]] && exit 3 # password protected pdf
echo "Some other error !"
fi
Please clarify me the following
Why awk behaves weird here? What I'm missing?
How to grep for a pattern in a string which contains special characters?
Does Ghostscript has any predefined error messages like that? If possible please suggest some documentation to refer..
Is it possible to compress password protected pdf with ghostscript?
How can i ensure for gs compression success in the above case? Since I may not know about different possible error which Ghostscript may throw so that i could cross check with my executed command result.
I am quite new to this shell script. Someone please help me on this.
PS: I have edited my question with additional details. Please look into it. If something has to be added i'll add it.
KenS's helpful answer addresses your questions about Ghostscript itself.
Here's a streamlined version of your code that should work:
# Run `gs` and capture its stderr output.
gs_res=$(gs -sDEVICE=pdfwrite -sOutputFile="$gsoutputfile" -dNOPAUSE -dBATCH "$2" 2>&1 1>/dev/null)
ec=$? # Save gs's exit code.
# Assume that something went wrong, IF:
# - gs reported a nonzero exit code
# - but *also* if any stderr output was produced, as
# not all problems may be reflected in a nonzero exit code.
if [[ $ec -ne 0 || -n $gs_res ]]; then
echo "Error message is :::::: $gs_res" >&2
gspassmsg='This file requires a password for access'
[[ $gs_res == *"$gspassmsg"* ]] && exit 3 # password protected pdf
fi
I've double-quoted the variable and parameter references in your gs command.
I've changed your redirection from just 2>&1 to 2>&1 1>/dev/null so as to only capture stderr output.
2>&1 redirects stderr (2) to the (still-original) stdout (1), so that error messages are sent to stdout and can be captured as part of the command substitution ($(...)); 1>/dev/null then redirects stdout to the null device, effectively silencing all stdout output. Note that the earlier redirection of stderr to the original stdout is not affected by this, so in effect what the overall command sends to stdout is the original stderr output only.
If you want to know more, see this answer of mine.
I'm using the more modern and flexible $(..) command-substitution syntax instead of the legacy `...` form (for background information, see here).
I've renamed GS_RES to gs_res, because it is better not to use all-uppercase shell-variable names in order to avoid conflicts with environment variables and special shell variables.
I'm using simple pattern matching to find the desired substring in gs's stderr output. Given that you already have the input to test against in a variable, Bash's own string-matching features will do (which are actually quite varied), and there is no need to use an external utility such as awk.
As for why your awk command failed:
It sounds like you're using BSD awk, such as the one that comes with macOS as of 10.12 (your question is tagged linux, however):
BSD awk doesn't support newlines in variable values passed via -v unless you \-escape the newlines.
With unescaped multi-line strings, your awk call fails fundamentally, before index() is ever called.
By contrast, GNU Awk and Mawk do support multi-line strings as-is passed via -v.
Read on for optional background information.
To determine which awk implementation you're using, run awk --version and examine the output:
awk version 20070501 -> BSD Awk
GNU Awk 4.1.3, API: 1.1 ... -> GNU Awk
mawk: not an option: --version -> Mawk
Here's a simple test to try with your Awk version:
awk -v a=$'1\n2' -v b=2 'BEGIN { print index(a, b) }'
Gnu Awk and Mawk output 3, as expected, whereas BSD Awk fails with awk: newline in string 1.
Also note that \-escaping newlines works ONLY in BSD Awk (e.g.,
awk -v var=$'1\\\n2' 'BEGIN { print var }'), which unfortunately means that there is no portable way to pass multi-line variable values to Awk.
Ghostscript's error messages all follow the same pattern, however there are some gotchas:
Part of the output is a dump of the operand stack at the time of the error. Since PostScript is a programming language, the contents of the stack depends on the program, and is entirely unpredictable. Even though you are dealing with PDF files, not PostScript programs, the interpreter is itself written in PostScript, so the same still applies.
The
'Error: /syntaxerror...'
is limited to a small number of actual possible errors, the PostScript Language Reference Manual defines them.
PostScript (but not PDF) programs can install an error handler, which can totally alter the error output, and even swallow the error altogether.
As regards 'compressing PDF files', that is absolutely not what you are doing. Please have a read here which explains what's actually happening. In short though, you are producing a new PDF file, not compressing an old one.
You can, of course, process a password protected PDF file with Ghostscript, as long as you know the password. Look for PDFPassword in the documentation here
Now the error message you quote above is not due to the file being encrypted (password protected), there's something else wrong with it. In fact given the simple command line you are using, I'd say there's something quite seriously wrong with it. Of course without seeing the file I can't tell for certain.
Now if a file is encrypted, the output from Ghostscript should read something like:
GPL Ghostscript GIT PRERELEASE 9.21 (2016-09-14)
Copyright (C) 2016 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
**** This file requires a password for access.
Error: /invalidfileaccess in pdf_process_Encrypt
Operand stack:
Execution stack: %interp_exit .runexec2 --nostringval--
--nostringval-- --nostringval-
- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- fa lse 1 %stopped_push 1983 1 3 %oparray_pop 1982 1 3 %oparray_ pop 1966 1 3
%oparray_pop --nostringval-- --nostringval-- --nostri ngval--
--nostringval-- false 1 %stopped_push Dictionary stack: --dict:1199/1684(ro)(G)-- --dict:1/20(G)-- --dict:83/200(L)-- --dict:83 /200(L)-- --dict:135/256(ro)(G)-- --dict:291/300(ro)(G)-- --dict:26/32(L)-
- Current allocation mode is local GPL Ghostscript GIT PRERELEASE 9.21: Unrecoverable error, exit code 1
So simply grepping for "This file requires a password" should be enough to identify encrypted files.
Now, as noted by mklement0, if you'd like to explain what it is about your actual script which is causing a problem, perhaps we can help with that too. You haven't shown the output of your script, or explained what is not working as you expect.

bash: Execute a string as a command

See my previous question on assembling a specific string here.
I was given an answer to that question, but unfortunately the information didn't actually help me accomplish what I was trying to achieve.
Using the info from that post, I have been able to assemble the following set of strings: gnuplot -e "filename='output_N.csv'" 'plot.p' where N is replaced by the string representation of an integer.
The following loop will explain: (Actually, there is probably a better way of doing this loop, which you may want to point out - hopefully the following code won't upset too many people...)
1 #!/bin/bash
2 n=0
3 for f in output_*.csv
4 do
5 FILE="\"filename='output_"$n".csv'\""
6 SCRIPT="'plot.p'"
7 COMMAND="gnuplot -e $FILE $SCRIPT"
8 $COMMAND
9 n=$(($n+1))
10 done
Unfortunately this didn't work... gnuplot does run, but gives the following error message:
"filename='output_0.csv'"
^
line 0: invalid command
"filename='output_1.csv'"
^
line 0: invalid command
"filename='output_2.csv'"
^
line 0: invalid command
"filename='output_3.csv'"
^
line 0: invalid command
...
So, as I said before, I'm no expert in bash. My guess is that something isn't being interpreted correctly - either something is being interpreted as a string where it shouldn't or it is not being interpreted as a string where it should? (Just a guess?)
How can I fix this problem?
The first few (relevant) line of my gnuplot script are the following:
(Note the use of the variable filename which was entered as a command line argument. See this link.)
30 fit f(x) filename using 1:4:9 via b,c,e
31
32 plot filename every N_STEPS using 1:4:9 with yerrorbars title "RK45 Data", f(x) title "Landau Model"
Easy fix - I made a mistake with the quotation marks. ("")
Essentially, the only reason why the quotation marks " and " are required around the text filename='output_"$n".csv' is so that this string is interpreted correctly by bash, before executing the command! So indeed it is correct that the program runs when the command gnuplot -e "filename='output_0.csv'" 'plot.p' is entered into the terminal directly, but the quotation marks are NOT required when assembling the string beforehand. (This is a bit difficult to explain, but hopefully it is clear in your mind the difference between the 2.)
So the corrected version of the above code is:
1 #!/bin/bash
2 n=0
3 for f in output_*.csv
4 do
5 FILE="filename='output_"$n".csv'"
6 SCRIPT='plot.p'
7 COMMAND="gnuplot -e $FILE $SCRIPT"
8 $COMMAND
9 n=$(($n+1))
10 done
That is now corrected and working. Note the removal of the escaped double quotes.

How can I add a footer to the bottom of each page of a postscript or pdf file in linux?

So I'd like to add a "footer" (an attribution) to the bottom of every page of a pdf file I am generating via postscript with groff in linux. I am converting the file from ps to pdf myself, with the ps2pdf tool, so I have access to both formats.
These two posts have been somewhat helpful:
How to add page numbers to Postscript/PDF
How can I make a program overlay text on a postscript file?
I'm not against using the first method, but I don't have access to the pdflatex utility mentioned in the first script, nor do I have the option to install it on the machine that needs to do the work.
It looks like the second method could possibly work, but I have version 8.15 of ghostscript installed and I didn't see many of the flags listed on the man page ( http://unix.browserdebug.com/man/gs/ ). I think I have access to the "-c" flag to insert some postscript code, even though it is not listed. Anyhow, here are two commands I tried unsuccessfully:
gs -o output.pdf -sDEVICE=pdfwrite -g5030x5320 \
-c "/Helvetica-Italic findfont 15 scalefont setfont 453 482 moveto (test-string) show" \
-f input.ps
that gives me this:
Unknown switch -o - ignoring
ESP Ghostscript 815.02 (2006-04-19)
Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
ERROR: /undefinedfilename in (output.pdf)
Operand stack:
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push
Dictionary stack:
--dict:1117/1686(ro)(G)-- --dict:0/20(G)-- --dict:102/200(L)--
Current allocation mode is local
Last OS error: 2
ESP Ghostscript 815.02: Unrecoverable error, exit code 1
So obviously the -o flag has a problem and so I did some research and tried this syntax:
gs -sOUTPUTFILE=output.pdf -sDEVICE=pdfwrite -g5030x5320 \
-c "/Helvetica-Italic findfont 15 scalefont setfont 453 482 moveto (test-string) show" \
-f input.ps
which outputs this and makes me hit return 4 times (maybe there are 4 pages in input.ps)
ESP Ghostscript 815.02 (2006-04-19)
Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Can't find (or can't open) font file /usr/share/ghostscript/8.15/Resource/Font/Helvetica-Italic.
Can't find (or can't open) font file Helvetica-Italic.
Querying operating system for font files...
Didn't find this font on the system!
Substituting font Helvetica-Oblique for Helvetica-Italic.
Loading NimbusSanL-ReguItal font from /usr/share/fonts/default/Type1/n019023l.pfb... 3742416 2168114 2083056 759694 1 done.
Loading NimbusRomNo9L-ReguItal font from /usr/share/fonts/default/Type1/n021023l.pfb... 3781760 2362033 2365632 1015713 1 done.
Loading NimbusRomNo9L-Medi font from /usr/share/fonts/default/Type1/n021004l.pfb... 3865136 2547267 2365632 1029818 1 done.
Loading NimbusRomNo9L-Regu font from /usr/share/fonts/default/Type1/n021003l.pfb... 4089592 2759001 2365632 1032885 1 done.
Using NimbusRomanNo9L-Regu font for NimbusRomNo9L-Regu.
>>showpage, press <return> to continue<<
>>showpage, press <return> to continue<<
>>showpage, press <return> to continue<<
>>showpage, press <return> to continue<<
So it seems like it would be simple enough to use gs to simply insert something in a ps file, but it is proving to be quite complicated...
In your PostScript file you can use a page counter and redefine showpage to display it in the footer. Here's a sample program:
4 dict begin
/showpage_org /showpage load def % you'll need this later!
/page_num 0 def
/page_str 3 string def % Page numbers -99 to 999 supported, error if > 3 char
/showpage % with page number footer
{
gsave
/Courier findfont 10 scalefont setfont % Set the font for the footer
/page_num page_num 1 add def % increment page number counter
10 10 moveto (Page ) show
page_num page_str cvs show % convert page number integer to a string and show it
grestore
showpage_org % use the original showpage
} def
%Page 1
/Courier findfont 22 scalefont setfont
100 500 moveto (Hello) show
showpage
%Page 2
100 500 moveto (World) show
showpage
end
ESP Ghostscript is O-o-o-o-old. Don't use it any more unless you absolutely, absolutely cannot avoid it. It was a fork of the original Ghostscript which used by CUPS for a while. (And after some problems between developers where resolved, more recent versions of CUPS now also use the GPL Ghostscript again...)
Newer GPL Ghostscript versions are here: http://www.ghostscript.com/releases/
Also, -o out.pdf is only a shorthand for -dBATCH -dNOPAUSE -sOutputFile=out.pdf. So you should try this. (The -dNOPAUSE part relieves you from hitting <return> for every page advance....).
Lastly, don't expect the full range of documentation being provided by a third party man gs page. Rather refer to the original Ghostscript documentation for the version you use, the most important parts being:
current development branch: Readme.htm + Use.htm + Ps2pdf.htm
9.00 release: Readme.htm + Use.htm + Ps2pdf.htm
8.71 release: Readme.htm + Use.htm + Ps2pdf.htm
Update: Ghostscript has moved to Git (instead of Subversion) for their source code repository. Therefor the following links have changed, repeatedly:
current development branch: Readme.htm + Use.htm + Ps2pdf.htm
current development branch: Readme.htm + Use.htm + Ps2pdf.htm
The most logical place to add page footers is in the groff source. The exact way to do this will of course depend on the macro package youre using. For -ms, you can do:
.ds RF "Page \\n(PN
to add the page number as right footer. For -mm, it's more like:
.PF "'''Page \\\\nP'"
where the single quotes delimit the 'left part'center part'right part' of the footer.

Resources