Search code examples
bashcopyrsync

Bash: How to handle brackets in filepath when passing as variable in pipe?


recently inherited some scripts and looking to find out what is going wrong with the following script, which aims to copy a specific TSV from multiple similar directories, over to a target directory while also renaming the TSV according to the source directory name:

#!/bin/bash
ls /output/analysed/out/reports/sourceDir/sourceFile_\(1.23\)_reviewed.tsv | awk -F'/' '{system("rsync -avrP "$0" "$6"_identifier.tsv")}'

This returns an error "/bin/sh: 1: Syntax error: "(" unexpected".

I understand it is related to the "$0" in my rsync command, as changing it helps get past the error. How should I pass this variable to rsync? Is there a better way to do this?


Solution

  • First of all, the error is not reported by bash, as you can see from the error message, but by sh, so I would replace the bash tag by the tags shell and awk. The rsync is executed by awk using sh.

    The following assumes that sourceFile_(1.23)_reviewed.tsv is a file (and not a directory):

    You are passing to system a string concatenated by 5 substrings: (1) rsync -avrP , (2) $0 (i.e. the whole input line from the ls), (3) a single space, (4) $6(i.e. the 6th field from the input), and (5)_identifier.tsv`.

    Since the output of ls must contain parenthesis (since actually you search for such a file with parentheses), the command to be executed will look like (for instance)

    rsync -avrP /output/analysed/out/reports/sourceDir/sourceFile_(1.23)_reviewed.tsv sourceDir
    

    This indeed shows illegal parenthesis.

    Since your ls command produces at most one line output (when the file is present), i.e. no output when the file does not exist, you could write your program easier as

    file="/output/analysed/out/reports/sourceDir/sourceFile_(1.23)_reviewed.tsv"
    [[ -r $file ]] && rsync -avrP "$file" sourceDir
    

    If you do want to use awk for whatever reason, you must ensure that the parenthesis get escaped when you pass them to sh.