1

I performed a file-command on all elements in my Desktop directory:

~/Desktop > file * 

then I grepped all the lines who have the string "image" in the description:

~/Desktop > file * | grep "image"

then I cut out only the file-name from the each line:

~/Desktop> file * | grep "image" | cut -d: -f1

From this step on, I do not know how to move all obtained filenames into one directory, I tried xargs, but I think I have a wrong understanding of it:

~/Desktop> file * | grep "image" | cut -d: -f1 | xargs mv {} ./dirk
1

2 Answers 2

1

Look at the --target-directory option to mv.

5
  • ikigai@ikigai-SATELLITE-L50D-B ~/Desktop $ file * | grep "image" | cut -d: -f1 | mv -t ./dirk mv: missing file operand Try 'mv --help' for more information. Mar 12, 2016 at 18:14
  • You'll still need xargs. Mar 12, 2016 at 18:58
  • i am at a loss, i tried different permutations like ...| xargs mv -t {} ./dirk with and without {} and so on... Mar 12, 2016 at 19:02
  • 1
    I don't have time to try, but it should be something like ...| xargs mv -t ./dirk Mar 12, 2016 at 19:18
  • you also need -d '\n' option with xargs to use newlines as the delimiter, otherwise xargs will treat filenames with space(s) in them as two (or more) filenames. -r aka --no-run-if-empty is also useful in case there are no matching filenames. e.g. ... | xargs -r -d '\n' mv -t ./dirk. Also, you should edit your answer to say more than just "look at the --target-directory option", you should explain what it does and why it's worth using in this situation. Otherwise, it's a correct answer, the lack of explanation is the only reason I haven't upvoted.
    – cas
    Mar 13, 2016 at 1:09
0

{} is not meaningful to xargs unless you pass the deprecated -i option or use -I {}.

file * | grep "image" | cut -d: -f1 | xargs -I {} mv {} ./dirk

This only works if your file names don't contain any special characters (:\"' or newline or an initial -; spaces work with xargs -I). This also includes filenames that contain images even though they aren't images. This includes files that the file command describes as “image” such as “disk image”, not just images as in pictures.

A more reliable (but not perfect) way to filter files whose content is a picture is to use file -i and look for files described as FILENAME: image/TYPE. The snippet below also converts quote characters that confuse some versions of xargs¹.

file -i ./* |
sed -n -e 's/["'\''\\]/\\&/' -e 's/: *image\/[^:]*$//p' |
xargs -I {} mv {} ./dirk

With reasonably recent versions of the GNU utilities (i.e. non-embedded Linux system or Cygwin), you can use null-separated lists to make the processing reliable and slightly faster.

file -0i ./* |
sed -z -e 's/: *image\/[^:]*$//p' |
xargs -0 mv -t ./dirk

Another approach, which has the benefit of working even if file * fails due to the command line length limit, is to use a loop or find to iterate over the files.

for x in ./*; do
  if [ -n "$(file -i "$x" | sed -n '$/: *image\/[^:]*$/ p')" ]; then
    mv "$x" ./dirk
  fi
done

¹ POSIX says that -I disables xargs's quote processing, but this is not the case in the GNU version as of findutils 4.4.2.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.