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.

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

3 Comments

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.
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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.