我在将我的 bash 命令转换为 shell 脚本中的 shell 脚本语法错误时遇到错误

Posted

技术标签:

【中文标题】我在将我的 bash 命令转换为 shell 脚本中的 shell 脚本语法错误时遇到错误【英文标题】:I'm facing an error while converting my bash comand to shell script syntax error in shell script 【发布时间】:2022-01-14 03:23:37 【问题描述】:
#!/bin/bash

set -o errexit
set -o nounset

#VAF_and_IGV_TAG

paste <(grep -v "^#" output/"$1"/"$1"_Variant_Filtering/"$1"_GATK_filtered.vcf | cut -f-5) \
      <(grep -v "^#" output/"$1"/"$1"_Variant_Filtering/"$1"_GATK_filtered.vcf | cut -f10-| cut -d ":" -f2,3) |
sed 's/:/\t/g' |
sed '1i chr\tstart\tend\tref\talt\tNormal_DP_VCF\tTumor_DP_VCF\tDP'|
awk 'BEGINFS=OFS="\t"sub(/,/,"\t",$6);print' \
  > output/"$1"/"$1"_Variant_Annotation/"$1"_VAF.tsv

如果我在终端中运行它而不使用它显示没有语法错误的变量,我的上面的代码最终会出现语法错误

sh Test.sh S1 Test.sh:6:Test.sh:语法错误:“(”意外

paste <(grep -v "^#" output/S1/S1_Variant_Filtering/S1_GATK_filtered.vcf | cut -f-5) \
      <(grep -v "^#" output/S1/S1_Variant_Filtering/S1_GATK_filtered.vcf | cut -f10-| cut -d ":" -f2,3) |
sed 's/:/\t/g' |
sed '1i chr\tstart\tend\tref\talt\tNormal_DP_VCF\tTumor_DP_VCF\tDP'|
awk 'BEGINFS=OFS="\t"sub(/,/,"\t",$6);print' \
  > output/S1/S1_Variant_Annotation/S1_VAF.ts

我的 vcf 文件如下所示:https://drive.google.com/file/d/1HaGx1-3o1VLCrL8fV0swqZTviWpBTGds/view?usp=sharing

【问题讨论】:

请edit在问题本身中提供一个(小)纯文本输入示例。 错误信息表明您正在使用sh 运行脚本。如果要使用 Bash 功能,则需要使用 bash。特别是,进程替换 &lt;(command) 不能移植到 POSIX sh 不清楚您是想将其转换为sh 脚本语法还是只是错误地运行代码。我已经发布了一个假设前者的答案,但我无法对其进行测试(拒绝连接到 Google Drive)。 @tripleee 我刚刚使用了 chmod 777 使我的程序可执行。然后我只是使用 bash test.sh 或 ./test.sh 运行它 无论您希望完成什么,chmod 777 都是错误危险的。您绝对不想这样做在任何情况下向所有用户授予对可执行文件或系统文件的写入权限。您将希望尽快恢复正常权限(对于您的用例,可能是chmod 755)并在尝试再次使用之前了解 Unix 权限模型。如果这种情况发生在可以访问 Internet 的系统上,请检查入侵者是否可以利用它来提升他们的权限。 【参考方案1】:

如果您尝试在sh 下运行此代码,则不能使用&lt;(command) 进程替换。不幸的是,没有优雅的方法可以避免临时文件(或者更可怕的东西),但是您的 paste 命令(实际上是整个管道)似乎相当容易重构为 Awk 脚本。

#!/bin/sh

set -eu

awk -F '\t' 'BEGIN  OFS=FS;
        print "chr\tstart\tend\tref\talt\tNormal_DP_VCF\tTumor_DP_VCF\tDP' 
    !/#/  p=$0; sub(/^([^\t]*\t)9/, "", p);
           sub(/^[:]*:/, "", p); sub(/:.*/, "", p);
           sub(/,/, "\t", p);
           s = sprintf("%s\t%s\t%s\t%s\t%s\t%s", $1, $2, $3, $4, $5, p);
           gsub(/:/, "\t", s);
           print s
    ' output/"$1"/"$1"_Variant_Filtering/"$1"_GATK_filtered.vcf \
  > output/"$1"/"$1"_Variant_Annotation/"$1"_VAF.tsv

由于无法访问 VCF 文件,我无法对此进行测试,但至少它应该为如何继续提供一个大致的方向。

【讨论】:

【参考方案2】:

sh 不支持bash 进程替换&lt;()。移植它的最简单方法是写出两个临时文件,并在完成时通过陷阱将它们删除。更好的选择是使用足够强大的工具(即 sed)来执行所需的过滤和操作:

#!/bin/sh
header="chr\tstart\tend\tref\talt\tNormal_DP_VCF\tTumor_DP_VCF\tDP"
field_1_to_5='\(\([^\t]*\t\)\5\\)' # \1 to \2
field_6_to_8='\([^\t]*\t\)\4\[^:]*:\([^,]*\),\([^:]*\):\([^:]*\).*' # \3 to \6
src="output/$1/$1_Variant_Filtering/$1_GATK_filtered.vcf"
dst="output/$1/$1_Variant_Variant_Annotation/$1_VAF.tsv"
sed -n \
  -e '1i '"$header" \
  -e '/^#/!s/'"$field_1_to_5$field_6_to_8"'/\1\4\t\5\t\6/p' \
  "$src" > "$dst"

如果您使用的是 awk(或 perl、python 等),只需将脚本移植到该语言即可。

顺便说一句,所有那些重复的$1 建议你应该修改你的文件命名标准。

【讨论】:

以上是关于我在将我的 bash 命令转换为 shell 脚本中的 shell 脚本语法错误时遇到错误的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉python在将命令传递给bash时忽略一个字符(Python到bash命令SyntaxError:因为{而无效的语法)

Shell 脚本之规范和变量

shell脚本报错:-bash:/bin/sh^M: bad interpreter:

如何将 Bash 命令的输出分配给变量? [复制]

运行 python 脚本运行 shell 文件时退出代码 191

在 bash 中使用单个命令为 shell 变量分配默认值