0

original file: a really really long name with spaces.ext
target file: the same name.new-ext

command: mv *part of the name that'll give a unique answer.ext $(echo $(ls -l | grep -i *.ext | cut -d ' ' -f 11-))

result: mv: target 'last word of the name.ext': No such file or directory

What am I doing wrong?

PS: the remote machine only allows sh (not even bash) so tab-completion is out of the picture.

kesarling He-Him
  • 159
  • 1
  • 18
  • can you copy and paste with a mouse? – jhnc Dec 11 '23 at 09:10
  • did you run your code through shellcheck per the shell tag description? you aren't quoting your arguments properly and note that grep -i *.ext probably doesn't do what you intend – jhnc Dec 11 '23 at 09:23

3 Answers3

2

You could do:

for f in *long*.ext; do mv -- "$f" "${f%.ext}.new-ext"; done

Or in several shells including dash and busybox ash (not hush), where $_ expands to the last argument of the previous command:

echo *long*

Check that it shows the right file, then:

mv -- "$_" "${_%.ext}.new-ext"
1

The number of spaces in ls -l output before the filename varies a lot and usually isn't 10. The number of characters also varies so cut -c isn't safe either.

But you don't need ls at all (and shouldn't want grep -i because that would take e.g. ExT instead) -- just $(echo *blah.ext |sed s/ext$/new-ext$/) would work.

(corrected) Even better in bash/ksh/zsh I would do f=(*ext); mv -- "$f" "${f%.ext}.new-ext" and consider inserting a safety check for ${#f[@]} -gt 1. If stuck on POSIX (e.g. dash, ash, busybox) could use set -- *blah.ext; if [ "$#" -eq 1 ]; then mv -- "$1" "${1%.ext}.new-ext"; else echo>&2 "error: $# files match"; fi.

  • note that posix shells support sourcing functions and executing scripts, so there's no reason to try to write a one-liner instead of clear/reusable/boring code. Since you are checking errors, don't forget handling when the destination already exists. – jhnc Dec 11 '23 at 05:20
  • @jhnc: I think $var and ${var-edited} is about as clear as you can get; do you have a better alternative? If you're repeating anything fairly often, a script or function is worth considering, but not for a single use, and this Q doesn't say either way. – dave_thompson_085 Dec 11 '23 at 05:49
  • But once you add any sanity checks the chances of mistyping the line (sh may not enable any line-editing beyond erase and kill) rises rapidly. Much more chance to mistype than change-ext -i "ext" "new-ext" glob-that-selects-relevant-files or somesuch. Personally, I just start vi, !!ls glob, do any edits, then pipe to sh, but it's possible the remote system doesn't even have an editor. – jhnc Dec 11 '23 at 09:08
  • 1
    @jhnc: simple (scalar) assignment is POSIX but doesn't glob. If run in process substitution (or more generally in a pipe) ls *ext does exactly the same as printf '%s\n' *ext for files but is wrong for subdirectories unless you add -d, and checking for multiples i.e. ambiguity is more complicated which you already complaineda bout. – dave_thompson_085 Dec 12 '23 at 07:39
  • yeah, I should have checked: no pathname expansion. not sure what command I must have run yesterday that made me think it did – jhnc Dec 12 '23 at 07:49
0

The easiest would be to make use of the rename command:

rename '.old' '.new' *'long'*'.old'

We are using quotes as any of the strings could contain spaces.

kvantour
  • 131