0

I have a bash script that I want to add a backslash in front of all underscores. The script searches for all files in a directory and saves the file name to a variable file. Then in the variable I want to replace every instance of _ with \_.

I have looked at several questions on sed about search and replace as well as how to treat special characters, but none of them seemed to apply correctly to this scenario.

#!/bin/bash
file=some_file_name.f90 # I want this to read as some\_file\_name.f90
# I have tried the following (and some more i didnt keep track of)
fileWithEscapedUnderscores=$(sed 's/_/\\_/g' <<<$file)
fileWithEscapedUnderscores=$(sed 's/_/\_/g' <<<$file)
fileWithEscapedUnderscores=$(sed 's/_/\\\_/g' <<<$file)
fileWithEscapedUnderscores=${file/_/\_/}

It seems like I need to escape the backslash. However, if I do that I can get the backslash but no underscore. I also tried simply inserting a backslash before the underscore, but that also had issues.

nikost
  • 788
  • 6
  • 14

1 Answers1

1

The simple and obvious solution is to escape or quote the backslash in the parameter expansion.

You also had the slashes wrong; your attempt would merely replace the first one, with the literal string \_/.

To recap, the syntax is ${variable/pattern/replacement} to replace the first occurrence of pattern, and ${variable//pattern/replacement} to replace all occurrences.

fileWithEscapedUnderscores=${file//_/\\_}
# or
fileWithEscapedUnderscores=${file//_/'\_'}

Your first sed attempt should have worked, too; but avoid calling an external process when you can use shell builtins.

Separately, probably take care to use quotes around variables with file names, though it would not matter in your example; see also When to wrap quotes around a shell variable

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • I see, those do work, including my first ```sed``` attempt. I tried to simplify my problem to create a minimal reproducible example. In the original program I loop through files passed to the script from a command line argument which is saved as ```files="$@"1```. Then I have a loop to change each file that begins as ```for file in ${files[@]}; do ```. At least now I know, or so it seems, this issues lies within how the list of files is looped though and now my search and replace command. Although, I am not sure why this would have an effect. – nikost Jan 21 '22 at 06:37
  • After some tests, the issue stems from how a list of files is stored when using globbing patters as opposed if a manually set a list of files to an array liike ```declare -a files=(some_filef90' 'another_file.f90')``` which works. – nikost Jan 21 '22 at 06:43
  • This answers the question you actually asked; perhaps (accept this answer, or post one of your own and accept that if you prefer. and) ask a new question if your actual problem is different. – tripleee Jan 21 '22 at 07:02