1

In bash, I have an unzipped directory where I have many file names that start with _.

I'm pretty sure I can use rename or mv to simply remove the _ prefix of each file that has it.

I try:

for file; do
    mv "$file" "${file//_/}"
done

But that doesn't have the effect I'd like. What command can I use to remove the _ prefix from all files?

4
  • In exactly what way does this not have the effect you want?
    – dhag
    Commented Feb 20, 2018 at 22:00
  • Well, for one, for file; do <stuff>; done is a syntax error.
    – DopeGhoti
    Commented Feb 20, 2018 at 22:01
  • 1
    In once instance, it didn't remove any underscore prefixes. In another, it removed all underscores in every filename that starts with the _ prefix
    – obidyne
    Commented Feb 20, 2018 at 22:02
  • @DopeGhoti: for x; do is a shortcut for for x in "$@"; do, so, assuming that the code is in its own script file, this may work (if called as e.g. script.sh _*). I understand that's a lot off assumptions :).
    – dhag
    Commented Feb 20, 2018 at 22:06

4 Answers 4

4

1) for file; do loops over the positional parameters, i.e. command line arguments to the script. Use for file in *; do to loop over the files in the directory (or _* to just take the ones with an underscore prefix.)

2) You can use ${file#_} instead of ${file//_/} to remove the underscore from the beginning of the filename. ${par#word} specifically removes a part from the beginning, and it's a standard feature, unlike ${par/pat/repl}. And of course ${file//_} would remove all slashes (since you used a double-slash), not just the first one.

3) at least on Linux (GNU userland) and FreeBSD, you can use mv -n to ask it to not overwrite any files. Just in case.

So,

for file in _*; do
    mv -n -- "$file" "${file#_}"
done
0
2

Simply with prename (Perl rename) command:

prename -n 's/^_//' _*
0

You're awfully close:

for file in _*; do
    if ! [[ -f "${file/_/}" ]]; then
        mv "$file" "${file/_/}"
    else
        echo "Replacement for '$file' already exists; skipping.." 1>&2
    fi
done

Why ${file/_/}? Because you specified an underscore prefix. So _file_name.ext will become file_name.ext. With ${file//_/}, _file_name.ext would become filename.ext.

1
  • I'm still new to bash ^_^
    – obidyne
    Commented Feb 20, 2018 at 22:04
0

You can use sed

for file in /some/path/*; do
    if [ -f "$file" ]; then
        mv "$file" `echo "$file" | sed 's*_**g'`
    fi
done
2
  • 1
    [ -e "$file" ] tests if a file of that name exists (regardless of its type). But you know it exists, since you just generated the name from a pattern match.
    – ilkkachu
    Commented Feb 20, 2018 at 22:07
  • @ilkkachu I was looking for -f. Wanted to know if it's a file and not a directory. My bad...
    – man0v
    Commented Feb 20, 2018 at 22:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .