views:

59

answers:

4

Hello,

I've got a simple enough question, but no guidance yet through the forums or bash. The question is as follows:

I want to add a prefix string to each filename in a directory that matches *.h or *.cpp. HOWEVER, if the prefix has already been applied to the filename, do NOT apply it again.

Why the following doesn't work is something that has yet to be figured out:

for i in *.{h,cpp}
do
if [[ $i!="$pattern*" ]]
then mv $i $pattern$i
fi
done
A: 
for i in *.{h,cpp}; do
  [ ${i#prefix} = $i ] && mv $i prefix$i
done

Not exactly conforming to your script, but it should work. The check returns true if there is no prefix (i.e. if $i, with the prefix "prefix" removed, equals $i).

roe
The ${i#prefix} should be ${i#$prefix}.But otheriwse this works. Thanks.
Display
@Display; no, it should perhaps be $pattern, I was referring to the literal prefix though.
roe
$pattern in both places that 'prefix' is used above, yes.
Display
Although this works, should the single '=' not be a double '==', or does the check in the guarded block '[...]' return true only if the left-hand side matches the right-hand side.
Display
'[ .. ]' is actually not a block, '[' is a command also known as test, with the added requirement that the last parameter is a ']' (hence, there must be a space between the '$i' and the ']'). And no, it should be a single `=`, although I don't think it's really picky about it.
roe
roe
A: 

you can try this:

for i in *.{h,cpp}
do
if ! ( echo $i | grep -q "^$pattern" ) 
# if the file does not begin with $pattern rename it.
then mv $i $pattern$i
fi
done
codaddict
Yes, this will do it - although it has the side effect of displaying grep's output on the (shell, stdin) - will need to turn that off
Display
@Display; grep -q will do that for you. Although, this is a fairly resource consuming solution. Thankfully echo is a built-in, so it'll shave some of the time off of it. Examining the strings directly would be preferable though.
roe
True. I would prefer not to use echo either.
Display
codaddict
grep in particular provides an analogy of reading the actual file rather than the filename string, resulting in wasted maintenance time in 5 years' time
Display
A: 
#!/bin/sh
pattern=testpattern_
for i in *.h *.cpp; do
  case "$i" in
     $pattern*)
        continue;;
      *)
        mv "$i" "$pattern$i";;
  esac
done

This script will run in any Posix shell, not just bash. (I wasn't sure if your question was "why isn't this working" or "how do I make this work" so I guessed it was the second.)

DigitalRoss
A: 

Others have shown replacements comparisons that work; I'll take a stab at why the original version didn't. There are two problems with the original prefix test: you need spaces between the comparison operator (!=) and its operands, and the asterisk was in quotes (meaning it gets matched literally, rather than as a wildcard). Fix these, and (at least in my tests) it works as expected:

if [[ $i != "$pattern"* ]]
Gordon Davisson