0

In How to move all files in current folder to subfolder?, the solution to moving all files from a folder but one is:

mv (!dontmovethis) /new/path/

When trying to move a file that includes a dash, a way to achieve this is:

mv -- '-dashie-file-' /new/path/

But what is the correct solution?

  1. If /new/path/ contains dashes: /new/-dash-path/
  2. If dontmovethis contains dashes: -dont-move-this.
  3. Both.

Naïvely trying out

mv -v -- (!'file-with-dash') '/new/path/with-dashes/'

produces the cryptic message (the -v is just to make mv more verbose):

bash: !'file: event not found

So this might be because bash is capturing the ! character. But, when escaped for bash;

mv -v -- (\!'file-with-dash') '/new/path/with-dashes/'
mv -v -- (\\!'file-with-dash') '/new/path/with-dashes/'
mv -v -- (\\\\!'file-with-dash') '/new/path/with-dashes/'
mv -v -- (\!file-with-dash) /new/path/with-dashes/

(Just trying out some ideas in confusion of how many layers of escaping are needed), all of these produce this:

bash: syntax error near unexpected token `(' 

Which leads me to believe mv is not de-escaping the full filename the same way when applying the ! operator. And finally, something like:

mv -v \(\!file-with-dash\) '/new/path/with-dashes'
mv -v \(\!'file-with-dash'\) '/new/path/with-dashes'

Produces:

mv: cannot stat '(!file-with-dash)': No such file or directory

Which means the ( is being escaped too much: mv is looking for a file literally named (!file-with-dash), while I want it to look for file-with-dash.

By the way, the second answer from that post can be easily adapted;

ls | grep -v dashing-file | xargs mv -t /new/dashing-folder

works straight away. There's one caveat to this method: If there's another file named dashing-file-with-evil-secrets that, being not the actual dashing-file, thus needs to be moved, gets caught by the grep. So it's not an exactly correct solution.

I just wonder if the top answer (the first code block in this post) can as well, as it does not have that caveat. Have not figured out a way to do this.

aphid
  • 123

1 Answers1

3

The syntax for the ksh-style extended glob is !(pattern) not (!pattern)

To exclude a the single file named -dashie-file- it would be !(-dashie-file-), or to exclude all files containing dashes you would use !(*-*), for example

mv !(-dashie-file-) path/to/newdir/

mv !(-) path/to/newdir/

You don't even need -- since the shell excludes the troublesome files before mv sees them (although it's good practice to include it), ex. given

$ ls
 -dashie-file-   dashing-file-with-evil-secrets  'other file'   somefile

then using ls in place of mv for the purpose of illustration

$ ls !(-dashie-file-)
 dashing-file-with-evil-secrets  'other file'   somefile

$ ls !(-) 'other file' somefile

steeldriver
  • 136,215
  • 21
  • 243
  • 336