Home > OS >  /bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: syntax error near unexpected token `('

Time:03-15

arg2 = f'cat <(grep \'#\' temp2.vcf) <(sort <(grep -v \'#\' temp2.vcf) | sortBed -i - | uniq ) > out.vcf'
print(arg2)
try:
    subprocess.call(arg2,shell=True)
except Exception as error:
    print(f'{error}')

While I'm running this I get the following error:

/bin/sh: -c: line 0: syntax error near unexpected token `('   
/bin/sh: -c: line 0: `cat <(grep '#' temp2.vcf) <(sort <(grep -v '#' temp2.vcf) | sortBed -i - | uniq ) > Out.vcf'

but when I run in the command line it works.

CodePudding user response:

The immediate error is that your attempt uses Bash-specific syntax. You can work around that with an executable="/bin/bash" keyword argument; but really, why are you using a complex external pipeline here at all? Python can do all these things except sortBed natively.

with open("temp2.vcf", "r"
      ) as vcfin, open("out.vcf", "w") as vcfout:
    sub = subprocess.Popen(
        ["sortBed", "-i", "-"],
        text=True,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE)

    for line in vcfin:
        if "#" in line:
            vcfout.write(line)
        else:
            sub.stdin.write(line)

    subout, suberr = sub.communicate()

    if suberr is not None:
        sys.stderr.write(suberr)

    seen = set()
    for line in subout.split("\n"):
        if line not in seen:
            vcfout.write(line   "\n")
        seen.add(line)

The Python reimplementation is slightly clunkier (and untested, as I don't have sortBed or your input data) but that also means it's more obvious where to change something if you want to modify it.

CodePudding user response:

Python's call() function invokes the command with sh by default. The process substitution syntax is supported by bash, but not by sh.

$ sh -c "cat <(date)"  
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `cat <(date)'

$ bash -c "cat <(date)"
Mon Mar 14 11:12:48 PDT 2022

I suggest rewriting your command as a more conventional pipeline, something like this:

arg2 = 'grep -v "#" temp2.vcf | sortBed -i - | uniq > out.vcf' 

It looks like you have some redundant steps in your command anyway.

If you really need to use the bash-specific syntax, you should be able to specify the shell executable (but I have not tried this):

subprocess.call(arg2, shell=True, executable='/bin/bash')
  • Related