0

Using the highlighted code at the bottom, I'm trying to achieve the output below:

/dir/subdir/file1.ext
/dir/subdir/file3.ext

However, everything I've tried does not give me the intended results and I always end up with nothing being removed or replaced. Is this even possible using this method or will I have to resort to something like sed?

#!/sbin/sh

testvar="/dir/subdir/file1.ext
/dir/subdir/file2.ext
/dir/subdir/file3.ext"

testvar=${testvar/\/dir\/subdir\/file2.ext\n}

echo $testvar

Thanks, everyone, for the responses. I've tried them all and did not have success with any of the suggestions. The only code that worked for me was the line below.

testvar=${testvar/?dir?subdir?file2.ext?}

Escaping the forward slashes '/' didn't work for me at all. And, while using the wild card '?' does the job, it's very slow in executing. I'll go with it if there's no other way, but if there's any further ideas left, I'd appreciate seeing them. Thanks, again.

3
  • Can you formalize your requirements? Do you want the fist two words of your string splitted at \n? And how do you want them? In one variable? How separated? Note that the shell does not expand \n in your example, so testvar contains a literal \n, not a newline. Commented Oct 3, 2014 at 20:21
  • 1
    It would also be interesting whether you are okay with using Bash features or need to be portable. Commented Oct 3, 2014 at 20:23
  • I've edited the sample script and removed the '\n'. This is actually how the problem variable in my script is created. Commented Oct 3, 2014 at 20:43

3 Answers 3

1

Answer to Revised Question

Three changes are needed to the script in the revised question:

#!/sbin/bash    
testvar="/dir/subdir/file1.ext
/dir/subdir/file2.ext
/dir/subdir/file3.ext"

testvar=${testvar/\/dir\/subdir\/file2.ext?}

echo "$testvar"

This script produces the output:

/dir/subdir/file1.ext
/dir/subdir/file3.ext

The three recommended changes are:

  1. Your script uses bash-specific features. So, the shebang line should reference bash. Depending on system defaults and how the script is invoked, this might not be necessary but, when using bash-specific features, it is always a good idea.

  2. In the parameter expansion, \n needs to be replaced with ?. This is because, as bash sees it, \n represents two characters, \ and n.

  3. To maintain the newlines in the output, $testvar needs to be inside double-quotes. Otherwise, word splitting occurs which causes newlines (and tabs if there were any) to be replaced with spaces.

Answer to Original Question

testvar=$'/dir/subdir/file1.ext\n/dir/subdir/file2.ext\n/dir/subdir/file3.ext'
testvar="${testvar/\/dir\/subdir\/file2.ext?/}"
echo "$testvar"

This produces the output:

/dir/subdir/file1.ext
/dir/subdir/file3.ext

Key points:

  • From your desired output, I infer that you wanted real newline characters rather than the two characters \n. So, testvar is defined using $'...'

  • To remove the blank line with the parameter expansion, it is necessary to match the newline character. This is done with a ? because in bash, again, the two characters \n do not match a newline.

  • If you want to keep the newlines when echo-ing testvar, then $testvar needs to be inside double-quotes. Otherwise, the newlines are converted to spaces.

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

Comments

0

You can use the ${variable##pattern} and ${variable%%pattern} syntax to strip something off the beginning or the end of a variable respectively.

Assuming I understood your requirements, you can use this to remove everything up to and including the first occurrence of a newline symbol in your string to extract the first and the last file name.

testvar="/dir/subdir/file1.ext
/dir/subdir/file2.ext
/dir/subdir/file3.ext"

# Store a newline inside a variable for convenience.
nl="
"

first="${testvar%%$nl*}"
last="${testvar##*$nl}"

echo "first: $first"
echo "last:  $last"

Output:

first: /dir/subdir/file1.ext
last:  /dir/subdir/file3.ext

You can read up the details of the syntax used here in the section 3.5.3 Shell Parameter Expansion in the Bash reference manual.

2 Comments

Thanks. I thought I was helping by adding the '\n'. It appears I may have actually confused the question. I've gone back and edited the sample script, removing the '\n' and adding the newline to the variable.
@TKruzze Okay, I have updated the answer accordingly.
0

Answer for revised question

$ testvar="/dir/subdir/file1.ext
> /dir/subdir/file2.ext
> /dir/subdir/file3.ext"
$ x=${testvar/\/dir\/subdir\/file2.ext
> }
$ echo "$x"
/dir/subdir/file1.ext
/dir/subdir/file3.ext
$

Note the newline embedded in the substitution. Also note that Bash doesn't map that properly in history (tested with both 3.2.53(1) from Apple and 4.3.27(2) built by me, on Mac OS X 10.9.5). The first line is obtained from history.

$ x=${testvar/\/dir\/subdir\/file2.ext; }
$ echo "$x"
/dir/subdir/file1.ext
/dir/subdir/file2.ext
/dir/subdir/file3.ext
$

Of course, that doesn't matter in a shell script.

Answer for original question

First note that $testvar does not contain any newlines:

$ testvar="/dir/subdir/file1.ext\n/dir/subdir/file2.ext\n/dir/subdir/file3.ext"
$ printf "%s\n" "$testvar"
/dir/subdir/file1.ext\n/dir/subdir/file2.ext\n/dir/subdir/file3.ext
$

Next, you need to match backslashes with double backslashes, and you need to match the \n before and after the middle /dir/subdir/file2.ext:

$ nl="
> "
$ x=${testvar/\\n\/dir\/subdir\/file2.ext\\n/$nl}
$ echo "$x"
/dir/subdir/file1.ext
/dir/subdir/file3.ext
$ printf "%s\n" "$x"
/dir/subdir/file1.ext
/dir/subdir/file3.ext
$

You can do it without the $nl variable, too:

$ x=${testvar/\\n\/dir\/subdir\/file2.ext\\n/
> }
$ echo "$x"
/dir/subdir/file1.ext
/dir/subdir/file3.ext
$

1 Comment

Thanks. I thought I was helping by adding the '\n'. It appears I may have actually confused the question. I've gone back and edited the sample script, removing the '\n' and adding the newline to the variable. – TKruzze just now

Your Answer

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