In the directory I am working on I have two files with the extension .sam:


For each of these two files, I need to apply a command that looks like the following:

samtools view -Sb pattern.sam > pattern.bam

I am trying to use xargs for that. What I am trying to do is to capture the prefix before _aligned_minimap and use that to save to my output. What I tried is the following:

ls *.sam | cut -d "_" -f 1 | xargs -i samtools view -Sb {}_aligned_minimap.sam > {}_aligned_minimap.bam

I would be expecting to have to files generated i.e. PD180425_aligned_minimap.bam and PD180793_aligned_minimap.bam. Although my command is running, I see on the directory I am working on that the file {}_aligned_minimap.bam was generated, which indicates that the input I am trying to capture with xargs (PD180425 and PD180793) is not working.

How can I go about doing this?


My preferred approach for this would be something like this:

for SAM_FILE in *.sam; do
    samtools view -Sb "$SAM_FILE" > "${SAM_FILE/sam/bam}"

Which can be made into a one liner like

for SAM_FILE in *.sam; do samtools view -Sb "$SAM_FILE" > "${SAM_FILE/sam/bam}"; done

This uses parameter expansion to change the output file extension: https://wiki.bash-hackers.org/syntax/pe

In my opinion this style makes it clear what you are trying to do if you or others stumble upon your scripts at a later time.

  • 4
    You can also use "${SAM_FILE%.sam}.bam" to change the extension. It has two advantages over ${//}: 1) it's a standard feature, unlike ${//}, so works in any sh-like shell, and 2) it makes the replacement only at the end of the string, so it doesn't matter if the middle of the filename contains sam.
    – ilkkachu
    Jul 26 '19 at 9:11

My command worked with slight modifications and I reckon it is simpler and less verbose than a for loop:

ls *.sam | cut -d "_" -f 1 | xargs -I {} bash -c " samtools view -Sb {}_aligned_minimap.sam > {}_aligned_minimap.bam"
  • Why do you think this is simpler or less verbose? Since you need 3 chained commands (4 if you count the bash -c script), instead of 1 for loop + 1 command. And in terms of characters it is almost 50% longer.
    – Lappro
    Aug 1 '19 at 8:57
  • less verbose because I have less semi-colons, uppercase characters (which is, in your case, simply convention) and special characters. Though I reckon this is just a matter of taste
    – BCArg
    Aug 2 '19 at 8:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.