Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing an optional / (directory separator) in Bash

Tags:

bash

replace

I have a Bash script that takes in a directory as a parameter, and after some processing will do some output based on the files in that directory.

The command would be like the following, where dir is a directory with the following structure inside

dir/foo
dir/bob
dir/haha
dir/bar
dir/sub-dir
dir/sub-dir/joe

> myscript ~/files/stuff/dir

After some processing, I'd like the output to be something like this

foo
bar
sub-dir/joe

The code I have to remove the path passed in is the following:

shopt -s extglob

for file in $files ; do
    filename=${file#${1}?(/)}

This gets me to the following, but for some reason the optional / is not being taken care of. Thus, my output looks like this:

/foo
/bar
/sub-dir/joe

The reason I'm making it optional is because if the user runs the command

> myscript ~/files/stuff/dir/

I want it to still work. And, as it stands, if I run that command with the trailing slash, it outputs as desired.

So, why does my ?(/) not work? Based on everything I've read, that should be the right syntax, and I've tried a few other variations as well, all to no avail.

Thanks.

like image 486
David Avatar asked Jan 05 '23 18:01

David


2 Answers

that other guy's helpful answer solves your immediate problem, but there are two things worth nothing:

  • enumerating filenames with an unquoted string variable (for file in $files) is ill-advised, as sjsam's helpful answer points out: it will break with filenames with embedded spaces and filenames that look like globs; as stated, storing filenames in an array is the robust choice.

  • there is no strict need to change global shell option shopt -s extglob: parameter expansions can be nested, so the following would work without changing shell options:

# Sample values:
file='dir/sub-dir/joe'
set -- 'dir/'  # set $1; value 'dir' would have the same effect.

filename=${file#${1%/}}  # -> '/sub-dir/joe'

The inner parameter expansion, ${1%/}, removes a trailing (%) / from $1, if any.

like image 182
mklement0 Avatar answered Jan 14 '23 21:01

mklement0


I suggested you change files to an array which is a possible workaround for non-standard filenames that may contain spaces.

files=("dir/A/B" "dir/B" "dir/C")
for filename in "${files[@]}"
do
  echo ${filename##dir/} #replace dir/ with your param.
done

Output

A/B
B
C
like image 28
sjsam Avatar answered Jan 14 '23 23:01

sjsam