【问题标题】:How to grep for a string pattern from command output in shell script?如何从 shell 脚本中的命令输出中获取字符串模式?
【发布时间】:2016-11-19 11:58:04
【问题描述】:

我正在使用 ghostscript 压缩我的 pdf 文件,这会在我必须处理的受密码保护的情况下引发错误。

Shell 脚本

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

而我的GS_RES执行命令后的值如下

错误信息 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

错误消息 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.

在错误消息 2 上运行 awk

gspassmsg="This file requires a password for access"
gspassworddoc=`awk -v a="$GS_RES" -v b="$gspassmsg" 'BEGIN{print index(a,b)}'`

它会抛出以下错误

错误:awk: newline in string GPL Ghostscript 9.19... at source line 1

错误信息 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.

我无法使用以下答案中的 sn-p 捕获此错误

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

请澄清以下内容

  1. 为什么awk 在这里表现得很奇怪?我错过了什么?
  2. 如何在包含特殊字符的字符串中查找模式?
  3. Ghostscript 是否有任何类似的预定义错误消息?如果可能,请建议一些文档以供参考..
  4. 是否可以使用 ghostscript 压缩受密码保护的 pdf?
  5. 在上述情况下如何确保 gs 压缩成功?由于我可能不知道 Ghostscript 可能抛出的不同可能错误,因此我可以与我执行的命令结果进行交叉检查。

我对这个 shell 脚本很陌生。有人请帮我解决这个问题。

PS:我已经用其他详细信息编辑了我的问题。请调查一下。如果有什么需要补充的,我会补充的。

【问题讨论】:

  • @mklement0 从命令输出中搜索字符串(例如“此文件需要密码才能访问”) - 将此过程称为grep
  • 当我的命令输出中包含一些特殊字符时,我不确定我猜awk 会播放有线。
  • 命令输出中的特殊字符类似于 (`, ") - 我已在错误消息 2 中添加。请查看。
  • 你是对的@mklement0。听起来不错!!超级:+1:
  • @subramanianrasapan:很高兴听到这个消息。我已经意识到这不仅仅是index():当您尝试将多行字符串作为变量值传递时,BSD Awk 从根本上失败,除非您\ -转义换行符。我的回答中有详细信息和替代解决方案。

标签: linux bash shell ghostscript


【解决方案1】:

KenS's helpful answer 解决您关于 Ghostscript 本身的问题。
这是您的代码的简化版本,应该可以工作:

# 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
  • 我在您的gs command 中引用了变量和参数引用。

  • 我已将您的重定向从 2>&1 更改为 2>&1 1>/dev/null,以便捕获标准错误输出。

    • 2>&1 将 stderr (2) 重定向到(仍然是原始的)stdout (1),以便将错误消息发送到 stdout,并且可以作为命令替换 ($(...)) 的一部分捕获; 1>/dev/null 然后将 stdout 重定向到 null 设备,有效地使所有 stdout 输出静音。请注意,stderr 到 original stdout 的 earlier 重定向不受此影响,因此实际上整个命令发送到 stdout 的内容是仅原始标准错误输出。
      如果您想了解更多信息,请参阅我的this answer
  • 我正在使用更现代、更灵活的$(..) 命令替换语法,而不是传统的`...` 形式(有关背景信息,请参阅here)。

  • 我已将 GS_RES 重命名为 gs_res,因为最好不要使用全大写的 shell 变量名称来代替 avoid conflicts with environment variables and special shell variables

  • 我正在使用简单的模式匹配在gs 的标准错误输出中找到所需的子字符串。鉴于您已经在变量中拥有要测试的输入,Bash 自己的字符串匹配功能就可以了(实际上是多种多样的),并且不需要使用诸如 awk 之类的外部实用程序。


至于为什么你的awk 命令失败

听起来你正在使用 BSD awk,例如 macOS 10.12 附带的那个(但是你的问题被标记为 linux):

BSD awk 不支持通过 -v 传递的变量值中的换行符,除非您 \-转义换行符。
使用未转义的多行字符串,在调用 index() 之前,您的 awk 调用基本上会失败。

相比之下,GNU Awk 和 Mawk 确实支持通过 -v 传递的多行字符串。

继续阅读可选背景信息


要确定您使用的是哪个awk 实现,请运行awk --version 并检查输出:

  • awk version 20070501 -> BSD awk

  • GNU Awk 4.1.3, API: 1.1 ... -> GNU awk

  • mawk: not an option: --version -> 毛克

这里有一个简单的测试,可以尝试使用您的 awk 版本:

awk -v a=$'1\n2' -v b=2 'BEGIN { print index(a, b) }'

Gnu Awk 和 Mawk 按预期输出 3,而 BSD Awk 失败并显示 awk: newline in string 1

另请注意,\-escaping newlines 仅适用于 BSD Awk(例如,
awk -v var=$'1\\\n2' 'BEGIN { print var }'),不幸的是,这意味着 没有可移植的方式来传递 multi -line 变量值到 Awk.

【讨论】:

  • 感谢您抽出宝贵时间@mklement0。如果我不问更多,你能解释一下2>&1 1>/dev/null 的作用吗?我对此没有任何想法。请帮我了解一下。
  • 我也在 linux 和 centos 中使用了这个awk
  • @subramanianrasapan:回复2>&1 1>/dev/null:请看我的更新。
  • @subramanianrasapan:我提到了awk 中的哪一个?运行awk --version 会得到什么?另请记住,没有必要使用awk 来解决您的问题,如我修改后的代码所示。
  • 我的“awk”版本返回为 GNU awk 4.0.2
【解决方案2】:

Ghostscript 的错误消息都遵循相同的模式,但是有一些陷阱:

部分输出是错误发生时操作数堆栈的转储。由于 PostScript 是一种编程语言,堆栈的内容取决于程序,并且是完全不可预测的。即使您处理的是 PDF 文件,而不是 PostScript 程序,解释器本身也是用 PostScript 编写的,所以同样适用。

'错误:/syntaxerror...'

仅限于少数实际可能出现的错误,PostScript 语言参考手册对它们进行了定义。

PostScript(但不是 PDF)程序可以安装错误处理程序,它可以完全改变错误输出,甚至完全吞下错误。

至于“压缩 PDF 文件”,这绝对是不是您正在做的事情。请阅读here,它解释了实际发生的情况。简而言之,您正在生成一个新的 PDF 文件,而不是压缩旧的。

当然,只要您知道密码,您就可以使用 Ghostscript 处理受密码保护的 PDF 文件。在文档中查找 PDFPassword here

现在您在上面引用的错误消息是不是,因为文件被加密(密码保护),还有其他问题。事实上,鉴于您使用的简单命令行,我会说它有一些非常严重的错误。当然没有看到文件我无法确定。

现在如果文件被加密,Ghostscript 的输出应该是这样的:

GPL Ghostscript GIT PRERELEASE 9.21 (2016-09-14) 版权所有 (C) 2016 Artifex Software, Inc. 保留所有权利。 此软件不提供任何保证:请参阅文件 PUBLIC 了解详细信息。

**** 此文件需要密码才能访问。

错误:pdf_process_Encrypt 中的 /invalidfileaccess

操作数栈:

执行堆栈:%interp_exit .runexec2 --nostringval--
--nostringval-- --nostringval- - 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- 错误 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 字典栈:--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)- - 当前分配模式是本地 GPL Ghostscript GIT PRERELEASE 9.21: Unrecoverable error, exit code 1

所以简单地搜索“此文件需要密码”就足以识别加密文件。

现在,正如 mklement0 所指出的,如果您想解释导致问题的实际脚本是什么,也许我们也可以提供帮助。您没有显示您的脚本的输出,或解释什么没有按您预期的那样工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    相关资源
    最近更新 更多