Search and Replace a Variable within Several Files

I have a directory full of CUE files. Each file contains a single reference to a varying filename.iso. The filename is within quotes and contains spaces. I need to do a search and replace that changes filename.iso to cuefilename.iso without .cue in the filename of course.

I had a similar issue where filename.iso was consistent in all of the filenames being processed, and the following kind of worked, aside from the resulting file containg filename.cue.iso instead of filename.iso

for x in *.cue; do sed -i “s/Track01.iso/$x/g” $x; done

so that’s my starting point, but I can’t figure out how to modify it for a variable filename.

Perhaps a simpler way of explaining my problem is that every filename.cue needs to point to filename.iso.

You can modify your command a little to do that.

In the body of your for loop, you could strip the .cue from the filename with stripped_filename=${x%.*} and you could modify your sed command to search for a regular expression instead of specifying the exact filename.

If the constraints of the filename is it is in quotes, contains spaces and ends in .iso, the expression \"[[:alnum:][:space:]]{1,}.iso\" matches (I think).

So the sed command would be sed -i -E "s?\"[[:alnum:][:space:]]{1,}.iso\"?\"$stripped _filename.iso\"?g" $x

The whole thing would look like:

for x in $(ls -1 | grep ".cue"); do \
    stripped_filename=${x%.*}; \
    sed -i -E "s?\"[[:alnum:][:space:]]{1,}.iso\"?\"$stripped_filename.iso\"?g" $cuefile; \
done

And when I run that on a test file:

clifford@Office-PC:/tmp$ echo "this is a test file that contains references to \"filenames in quotes with spaces.iso\" that should be replaced with references to the containing filename instead of \"filenames in quotes with spaces.iso\"" > testfile.cue
clifford@Office-PC:/tmp$ for x in $(ls -1 | grep ".cue"); do stripped_filename=${x%.*}; sed -i -E "s?\"[[:alpha:][:space:]]{1,}.iso\"?\"$stripped_filename.iso\"?g" $x; done

The resulting file contains:

clifford@Office-PC:/tmp$ cat testfile.cue
this is a test file that contains references to "testfile.iso" that should be replaced with references to the containing filename instead of "testfile.iso"

You may have to tweak the regular expression to match your exact pattern.

2 Likes

I guess I failed to specify that the cue filenames also contain spaces. I played with it some more based on your suggestion, but failed to get it working. I really appreciate your help!

âžś  temp cat Title\ of\ a\ Thing\ \(USA\).cue 
CATALOG 0000000000000
FILE "Title of a Thing (1994)(GTE)(US)[!].iso" BINARY
  TRACK 01 MODE1/2048
    INDEX 01 00:00:00

âžś  temp for x in $(ls -1 | grep ".cue"); do stripped_filename=${x%.*}; sed -i -E "s?\"[[:alpha:][:space:]]{1,}.iso\"?\"$stripped_filename.iso\"?g" $x; done
sed: can't read Title: No such file or directory
sed: can't read of: No such file or directory
sed: can't read a: No such file or directory
sed: can't read Thing: No such file or directory
sed: can't read (USA).cue: No such file or directory

I think if you add IFS=$'\n'; prior to the for loop, then each x will break on newline characters and not the spaces.

If wrap the sed command’s input file in quotes it should handle the spaces "$x".

And based on your file name and contents, tweak the regex to match the parenthesis and punctuation: \"[[:alnum:][:space:][:punct:]\(\)]{1,}.iso\"?\"

IFS=$'\n'; for x in $(ls -1 | grep ".cue"); do stripped_filename=${x%.*}; sed -i -E "s?\"[[:alnum:][:space:][:punct:]\(\)]{1,}.iso\" ?\"$stripped_filename.iso\"?g" "$x"; done

I think that works. Your original “Title of a Thing (USA).cue”:

clifford@Office-PC:/tmp$ cat "Title of a Thing (USA).cue"
CATALOG 0000000000000
FILE "Title of a Thing (1994)(GTE)(US)[!].iso" BINARY
  TRACK 01 MODE1/2048
    INDEX 01 00:00:00

command:

clifford@Office-PC:/tmp$ IFS=$'\n'; \
    for x in $(ls -1 | grep ".cue"); do \
        stripped_filename=${x%.*}; \
        sed -i -E "s?\"[[:alnum:][:space:][:punct:]\(\)]{1,}.iso\"?\"$stripped_filename.iso\"?g" "$x"; 
    done

edited file:

clifford@Office-PC:/tmp$ cat "Title of a Thing (USA).cue"
CATALOG 0000000000000
FILE "Title of a Thing (USA).iso" BINARY
  TRACK 01 MODE1/2048
    INDEX 01 00:00:00

If the original filenames have more characters, you just have to keep adding to the regex pattern.

1 Like

The \(\) in the regex pattern is redundant. I didn’t remember parenthesis were included [:punct:].

Perfect! You freakin’ rock!

1 Like