‘Well it’s only passing mv a list of–’ yeah yeah yeah, I know, and that’s why I’m calling bullshit. It should be massively harder to execute filenames. Even if 1970s decisions make that the eternal hideous default: the lack of any idiot-proof standard workaround is incomprehensible.
StackOverflow’s full of competing one-liners and people pointing out how each one is considered harmful. The least-skeezy options use exec. That sentence should make anyone recoil in horror.
This is not a filename problem. This is a tool problem. If a single printable character is going to silently expand into a list of names, then for god’s sake, having it put each name in quotes should be fucking trivial.
I have two questions:
I’m using bash (
GNU bash, version 5.1.16(1)-release
) and don’t observe this behavior:$ ls 'first file.txt' 'second file.txt' $ cat 'first file.txt' this is originally named "first file.txt" $ cat 'second file.txt' this is originally named "second file.txt" $ mv *.txt $ ls 'second file.txt' $ cat 'second file.txt' this is originally named "first file.txt"
It’s possible that whatever shell you’re using has a bug, but it’s definitely not universal. It’s also possible that this bug only affects builtins like
mv
and not non-builtin commands.I expected people have tried to move files… using the move command.
I did not expect I’d have to specify that there’s a destination, in an explanation of what
*.jpg
does, not an explanation of whatmv
does.For clarity:
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
mv *.jpg /mnt/Example/Pictures
Where it will then die with an error like
mv: invalid option -- '1'
depending on the contents of the current directory.Every search about this has led back to this StackOverflow page sooner or later. All answers address wildcard expansion.
Can you run
printf %s\\n *.jpg
in that same directory and share the result? I’m really intrigued. If there’s private information in there, I’d be satisfied with just a handful of lines showing the issue with private info replaced with ****sEdit: also run
alias mv
to check whether you have an alias messing things upbash: alias: mv: not found
printf %s\\n *.jpg
is just a list of filenames on newlines. There’s 75,000 of them. You’ll have to take my word for it.Fortunately, GenderNeutralBro’s aside about using
./*
instead of*
works as expected. Could have been files beginning with_-
. None begin with-
, exactly.When I run into situations like this, I use the commands that work to write out a script. Eg, in your case the wildcard isn’t working with the mv command, so do something like this:
ls -1 *.jpg | awk ‘{print “mv "”$1"" /mnt/example/Pictures"}’ > /tmp/movefiles.sh
Then check the movefiles.sh and make sure it has all of the commands and files properly stated, make that executable, and then run that.
ls | grep | mv
would work, except the StackOverflow discussion also highlights how parsing ls can have the same issues.I am moving thousands of files at once. If I have to check each one, it’s still wrong.
The pragmatic answer turns out to be
./*
instead of*
.I saw that answer and was just offering another option. I am sure xargs might work, but you would need to test as you need a destination passed on each line. Back to my way, I have used it for a lot more than just the move command. I think I used it to do a chmod once where I wanted to check and make sure before I committed to actually running the command(s). You could also use find and the -exec option, which I think was also mentioned here.
Edit: also, you wouldn’t need to check each one, just the first few and last few to make sure the syntax is correct. Maybe do a wc -l to make sure it’s got the right number of entries and then let it run.