Solving “mv: Argument list too long”?












54















I have a folder with more than a million files that needs sorting, but I can't really do anything because mv outputs this message all the time



-bash: /bin/mv: Argument list too long


I'm using this command to move extension-less files:



mv -- !(*.jpg|*.png|*.bmp) targetdir/









share|improve this question

























  • Related: Does "argument list too long" restriction apply to shell builtins?

    – codeforester
    Nov 22 '17 at 21:16
















54















I have a folder with more than a million files that needs sorting, but I can't really do anything because mv outputs this message all the time



-bash: /bin/mv: Argument list too long


I'm using this command to move extension-less files:



mv -- !(*.jpg|*.png|*.bmp) targetdir/









share|improve this question

























  • Related: Does "argument list too long" restriction apply to shell builtins?

    – codeforester
    Nov 22 '17 at 21:16














54












54








54


12






I have a folder with more than a million files that needs sorting, but I can't really do anything because mv outputs this message all the time



-bash: /bin/mv: Argument list too long


I'm using this command to move extension-less files:



mv -- !(*.jpg|*.png|*.bmp) targetdir/









share|improve this question
















I have a folder with more than a million files that needs sorting, but I can't really do anything because mv outputs this message all the time



-bash: /bin/mv: Argument list too long


I'm using this command to move extension-less files:



mv -- !(*.jpg|*.png|*.bmp) targetdir/






bash shell arguments mv






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 17 '16 at 15:08









Jeff Schaller

39.9k1054126




39.9k1054126










asked May 8 '14 at 23:31









DominiqueDominique

1,35051821




1,35051821













  • Related: Does "argument list too long" restriction apply to shell builtins?

    – codeforester
    Nov 22 '17 at 21:16



















  • Related: Does "argument list too long" restriction apply to shell builtins?

    – codeforester
    Nov 22 '17 at 21:16

















Related: Does "argument list too long" restriction apply to shell builtins?

– codeforester
Nov 22 '17 at 21:16





Related: Does "argument list too long" restriction apply to shell builtins?

– codeforester
Nov 22 '17 at 21:16










8 Answers
8






active

oldest

votes


















79














xargs is the tool for the job. That, or find with -exec … {} +. These tools run a command several times, with as many arguments as can be passed in one go.



Both methods are easier to carry out when the variable argument list is at the end, which isn't the case here: the final argument to mv is the destination. With GNU utilities (i.e. on non-embedded Linux or Cygwin), the -t option to mv is useful, to pass the destination first.



If the file names have no whitespace nor any of "', then you can simply provide the file names as input to xargs (the echo command is a bash builtin, so it isn't subject to the command line length limit):



echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir


You can use the -0 option to xargs to use null-delimited input instead of the default quoted format.



printf '%s' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir


Alternatively, you can generate the list of file names with find. To avoid recursing into subdirectories, use -type d -prune. Since no action is specified for the listed image files, only the other files are moved.



find . -name . -o -type d -prune -o 
-name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
-exec mv -t targetdir/ {} +


(This includes dot files, unlike the shell wildcard methods.)



If you don't have GNU utilities, you can use an intermediate shell to get the arguments in the right order. This method works on all POSIX systems.



find . -name . -o -type d -prune -o 
-name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
-exec sh -c 'mv "$@" "$0"' targetdir/ {} +




In zsh, you can load the mv builtin:



setopt extended_glob
zmodload zsh/files
mv -- ^*.(jpg|png|bmp) targetdir/


or if you prefer to let mv and other names keep referring to the external commands:



setopt extended_glob
zmodload -Fm zsh/files b:zf_*
zf_mv -- ^*.(jpg|png|bmp) targetdir/


or with ksh-style globs:



setopt ksh_glob
zmodload -Fm zsh/files b:zf_*
zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/


Alternatively, using GNU mv and zargs:



autoload -U zargs
setopt extended_glob
zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/





share|improve this answer





















  • 1





    The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

    – Dominique
    May 9 '14 at 1:44











  • @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

    – Gilles
    May 9 '14 at 1:50











  • I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

    – Dominique
    May 9 '14 at 1:56











  • @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

    – Gilles
    May 9 '14 at 1:58













  • Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

    – CivFan
    Oct 23 '15 at 21:15





















9














The operating system's argument passing limit does not apply to expansions which happen within the shell interpreter. So in addition to using xargs or find, we can simply use a shell loop to break up the processing into individual mv commands:



for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done


This uses only POSIX Shell Command Language features and utilities. This one-liner is clearer with indentation, with unnecessary semicolons removed:



for x in *; do
case "$x" in
*.jpg|*.png|*.bmp)
;; # nothing
*) # catch-all case
mv -- "$x" target
;;
esac
done





share|improve this answer


























  • With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

    – CivFan
    Oct 23 '15 at 20:48













  • @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

    – Kaz
    Oct 23 '15 at 20:51













  • -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

    – CivFan
    Oct 23 '15 at 21:33













  • Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

    – Kaz
    Oct 24 '15 at 0:29



















5














For a more aggressive solution than those previously offered, pull up your kernel source and edit include/linux/binfmts.h



Increase the size of MAX_ARG_PAGES to something larger than 32. This increases the amount of memory the kernel will allow for program arguments, thereby allowing you to specify your mv or rm command for a million files or whatever you're doing. Recompile, install, reboot.



BEWARE! If you set this too large for your system memory, and then run a command with a lot of arguments BAD THINGS WILL HAPPEN! Be extremely cautious doing this to multi-user systems, it makes it easier for malicious users to use up all your memory!



If you don't know how to recompile and reinstall your kernel manually, it's probably best that you just pretend this answer doesn't exist for now.






share|improve this answer

































    4














    A more simple solution using "$origin"/!(*.jpg|*.png|*.bmp) instead of a catch block:





    for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done


    Thanks to @Score_Under



    For a multi-line script you can do the following (notice the ; before the done is dropped):



    for file in "$origin"/!(*.jpg|*.png|*.bmp); do        # don't copy types *.jpg|*.png|*.bmp
    mv -- "$file" "$destination"
    done


    To do a more generalized solution that moves all files, you can do the one-liner:



    for file in "$origin"/*; do mv -- "$file" "$destination" ; done


    Which looks like this if you do indentation:



    for file in "$origin"/*; do
    mv -- "$file" "$destination"
    done


    This takes every file in the origin and moves them one by one to the destination. The quotes around $file are necessary in case there are spaces or other special characters in the filenames.



    Here is an example of this method that worked perfectly



    for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
    mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
    done





    share|improve this answer


























    • You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

      – Score_Under
      Jun 20 '15 at 0:34











    • What do you mean original glob?

      – Whitecat
      Jun 20 '15 at 0:38











    • Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

      – Score_Under
      Jun 21 '15 at 3:52











    • Awesome Score. I incorporated your comment and updated my answer.

      – Whitecat
      Jun 27 '15 at 22:55



















    3














    If working with Linux kernel is enough you can simply do



    ulimit -s 100000


    that will work because Linux kernel included a patch around 10 years ago that changed argument limit to be based on stack size: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba



    Update: If you feel brave, you can say



    ulimit -s unlimited


    and you'll be fine with any shell expansions as long as you have enough RAM.






    share|improve this answer


























    • That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

      – Kusalananda
      Nov 1 '17 at 9:38











    • Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

      – Mikko Rantalainen
      Nov 3 '17 at 13:00











    • With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

      – Mikko Rantalainen
      Jun 8 '18 at 7:01





















    1














    You can get around that restriction while still using mv if you don't mind running it a couple times.



    You can move portions at a time. Let's say for example you had a long list of alphanumeric file names.



    mv ./subdir/a* ./


    That works. Then knock out another big chunk. After a couple moves, you can just go back to using mv ./subdir/* ./






    share|improve this answer































      0














      Sometimes it's easiest to just write a little script, e.g. in Python:



      import glob, shutil

      for i in glob.glob('*.jpg'):
      shutil.move(i, 'new_dir/' + i)





      share|improve this answer































        0














        Here is my two cents, append this into .bash_profile



        mv() {
        if [[ -d $1 ]]; then #directory mv
        /bin/mv $1 $2
        elif [[ -f $1 ]]; then #file mv
        /bin/mv $1 $2
        else
        for f in $1
        do
        source_path=$f
        #echo $source_path
        source_file=${source_path##*/}
        #echo $source_file
        destination_path=${2%/} #get rid of trailing forward slash

        echo "Moving $f to $destination_path/$source_file"

        /bin/mv $f $destination_path/$source_file
        done
        fi
        }
        export -f mv


        Usage



        mv '*.jpg' ./destination/
        mv '/path/*' ./destination/




        share








        New contributor




        Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.




















          Your Answer








          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "106"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f128559%2fsolving-mv-argument-list-too-long%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          8 Answers
          8






          active

          oldest

          votes








          8 Answers
          8






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          79














          xargs is the tool for the job. That, or find with -exec … {} +. These tools run a command several times, with as many arguments as can be passed in one go.



          Both methods are easier to carry out when the variable argument list is at the end, which isn't the case here: the final argument to mv is the destination. With GNU utilities (i.e. on non-embedded Linux or Cygwin), the -t option to mv is useful, to pass the destination first.



          If the file names have no whitespace nor any of "', then you can simply provide the file names as input to xargs (the echo command is a bash builtin, so it isn't subject to the command line length limit):



          echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir


          You can use the -0 option to xargs to use null-delimited input instead of the default quoted format.



          printf '%s' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir


          Alternatively, you can generate the list of file names with find. To avoid recursing into subdirectories, use -type d -prune. Since no action is specified for the listed image files, only the other files are moved.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec mv -t targetdir/ {} +


          (This includes dot files, unlike the shell wildcard methods.)



          If you don't have GNU utilities, you can use an intermediate shell to get the arguments in the right order. This method works on all POSIX systems.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec sh -c 'mv "$@" "$0"' targetdir/ {} +




          In zsh, you can load the mv builtin:



          setopt extended_glob
          zmodload zsh/files
          mv -- ^*.(jpg|png|bmp) targetdir/


          or if you prefer to let mv and other names keep referring to the external commands:



          setopt extended_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- ^*.(jpg|png|bmp) targetdir/


          or with ksh-style globs:



          setopt ksh_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/


          Alternatively, using GNU mv and zargs:



          autoload -U zargs
          setopt extended_glob
          zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/





          share|improve this answer





















          • 1





            The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

            – Dominique
            May 9 '14 at 1:44











          • @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

            – Gilles
            May 9 '14 at 1:50











          • I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

            – Dominique
            May 9 '14 at 1:56











          • @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

            – Gilles
            May 9 '14 at 1:58













          • Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

            – CivFan
            Oct 23 '15 at 21:15


















          79














          xargs is the tool for the job. That, or find with -exec … {} +. These tools run a command several times, with as many arguments as can be passed in one go.



          Both methods are easier to carry out when the variable argument list is at the end, which isn't the case here: the final argument to mv is the destination. With GNU utilities (i.e. on non-embedded Linux or Cygwin), the -t option to mv is useful, to pass the destination first.



          If the file names have no whitespace nor any of "', then you can simply provide the file names as input to xargs (the echo command is a bash builtin, so it isn't subject to the command line length limit):



          echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir


          You can use the -0 option to xargs to use null-delimited input instead of the default quoted format.



          printf '%s' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir


          Alternatively, you can generate the list of file names with find. To avoid recursing into subdirectories, use -type d -prune. Since no action is specified for the listed image files, only the other files are moved.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec mv -t targetdir/ {} +


          (This includes dot files, unlike the shell wildcard methods.)



          If you don't have GNU utilities, you can use an intermediate shell to get the arguments in the right order. This method works on all POSIX systems.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec sh -c 'mv "$@" "$0"' targetdir/ {} +




          In zsh, you can load the mv builtin:



          setopt extended_glob
          zmodload zsh/files
          mv -- ^*.(jpg|png|bmp) targetdir/


          or if you prefer to let mv and other names keep referring to the external commands:



          setopt extended_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- ^*.(jpg|png|bmp) targetdir/


          or with ksh-style globs:



          setopt ksh_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/


          Alternatively, using GNU mv and zargs:



          autoload -U zargs
          setopt extended_glob
          zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/





          share|improve this answer





















          • 1





            The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

            – Dominique
            May 9 '14 at 1:44











          • @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

            – Gilles
            May 9 '14 at 1:50











          • I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

            – Dominique
            May 9 '14 at 1:56











          • @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

            – Gilles
            May 9 '14 at 1:58













          • Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

            – CivFan
            Oct 23 '15 at 21:15
















          79












          79








          79







          xargs is the tool for the job. That, or find with -exec … {} +. These tools run a command several times, with as many arguments as can be passed in one go.



          Both methods are easier to carry out when the variable argument list is at the end, which isn't the case here: the final argument to mv is the destination. With GNU utilities (i.e. on non-embedded Linux or Cygwin), the -t option to mv is useful, to pass the destination first.



          If the file names have no whitespace nor any of "', then you can simply provide the file names as input to xargs (the echo command is a bash builtin, so it isn't subject to the command line length limit):



          echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir


          You can use the -0 option to xargs to use null-delimited input instead of the default quoted format.



          printf '%s' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir


          Alternatively, you can generate the list of file names with find. To avoid recursing into subdirectories, use -type d -prune. Since no action is specified for the listed image files, only the other files are moved.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec mv -t targetdir/ {} +


          (This includes dot files, unlike the shell wildcard methods.)



          If you don't have GNU utilities, you can use an intermediate shell to get the arguments in the right order. This method works on all POSIX systems.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec sh -c 'mv "$@" "$0"' targetdir/ {} +




          In zsh, you can load the mv builtin:



          setopt extended_glob
          zmodload zsh/files
          mv -- ^*.(jpg|png|bmp) targetdir/


          or if you prefer to let mv and other names keep referring to the external commands:



          setopt extended_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- ^*.(jpg|png|bmp) targetdir/


          or with ksh-style globs:



          setopt ksh_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/


          Alternatively, using GNU mv and zargs:



          autoload -U zargs
          setopt extended_glob
          zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/





          share|improve this answer















          xargs is the tool for the job. That, or find with -exec … {} +. These tools run a command several times, with as many arguments as can be passed in one go.



          Both methods are easier to carry out when the variable argument list is at the end, which isn't the case here: the final argument to mv is the destination. With GNU utilities (i.e. on non-embedded Linux or Cygwin), the -t option to mv is useful, to pass the destination first.



          If the file names have no whitespace nor any of "', then you can simply provide the file names as input to xargs (the echo command is a bash builtin, so it isn't subject to the command line length limit):



          echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir


          You can use the -0 option to xargs to use null-delimited input instead of the default quoted format.



          printf '%s' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir


          Alternatively, you can generate the list of file names with find. To avoid recursing into subdirectories, use -type d -prune. Since no action is specified for the listed image files, only the other files are moved.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec mv -t targetdir/ {} +


          (This includes dot files, unlike the shell wildcard methods.)



          If you don't have GNU utilities, you can use an intermediate shell to get the arguments in the right order. This method works on all POSIX systems.



          find . -name . -o -type d -prune -o 
          -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o
          -exec sh -c 'mv "$@" "$0"' targetdir/ {} +




          In zsh, you can load the mv builtin:



          setopt extended_glob
          zmodload zsh/files
          mv -- ^*.(jpg|png|bmp) targetdir/


          or if you prefer to let mv and other names keep referring to the external commands:



          setopt extended_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- ^*.(jpg|png|bmp) targetdir/


          or with ksh-style globs:



          setopt ksh_glob
          zmodload -Fm zsh/files b:zf_*
          zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/


          Alternatively, using GNU mv and zargs:



          autoload -U zargs
          setopt extended_glob
          zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Sep 17 '14 at 21:41

























          answered May 8 '14 at 23:48









          GillesGilles

          533k12810721594




          533k12810721594








          • 1





            The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

            – Dominique
            May 9 '14 at 1:44











          • @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

            – Gilles
            May 9 '14 at 1:50











          • I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

            – Dominique
            May 9 '14 at 1:56











          • @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

            – Gilles
            May 9 '14 at 1:58













          • Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

            – CivFan
            Oct 23 '15 at 21:15
















          • 1





            The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

            – Dominique
            May 9 '14 at 1:44











          • @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

            – Gilles
            May 9 '14 at 1:50











          • I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

            – Dominique
            May 9 '14 at 1:56











          • @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

            – Gilles
            May 9 '14 at 1:58













          • Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

            – CivFan
            Oct 23 '15 at 21:15










          1




          1





          The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

          – Dominique
          May 9 '14 at 1:44





          The first two commands returned "-bash: !: event not found" and the next two did not move any files at all. I'm on CentOS 6.5 if you should know

          – Dominique
          May 9 '14 at 1:44













          @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

          – Gilles
          May 9 '14 at 1:50





          @Dominique I used the same globbing syntax that you used in your question. You'll need shopt -s extglob to enable it. I'd missed a step in the find commands, I've fixed them.

          – Gilles
          May 9 '14 at 1:50













          I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

          – Dominique
          May 9 '14 at 1:56





          I'm getting this with the find command "find: invalid expression; you have used a binary operator '-o' with nothing before it." I will now try the other ones.

          – Dominique
          May 9 '14 at 1:56













          @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

          – Gilles
          May 9 '14 at 1:58







          @Dominique The find commands I've posted (now) work. You must have left off a part when copy-pasting.

          – Gilles
          May 9 '14 at 1:58















          Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

          – CivFan
          Oct 23 '15 at 21:15







          Gilles, for the find commands, why not use the "not" operator, !? It's more explicit and easier to understand than the odd trailing -o. For example, ! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'

          – CivFan
          Oct 23 '15 at 21:15















          9














          The operating system's argument passing limit does not apply to expansions which happen within the shell interpreter. So in addition to using xargs or find, we can simply use a shell loop to break up the processing into individual mv commands:



          for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done


          This uses only POSIX Shell Command Language features and utilities. This one-liner is clearer with indentation, with unnecessary semicolons removed:



          for x in *; do
          case "$x" in
          *.jpg|*.png|*.bmp)
          ;; # nothing
          *) # catch-all case
          mv -- "$x" target
          ;;
          esac
          done





          share|improve this answer


























          • With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

            – CivFan
            Oct 23 '15 at 20:48













          • @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

            – Kaz
            Oct 23 '15 at 20:51













          • -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

            – CivFan
            Oct 23 '15 at 21:33













          • Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

            – Kaz
            Oct 24 '15 at 0:29
















          9














          The operating system's argument passing limit does not apply to expansions which happen within the shell interpreter. So in addition to using xargs or find, we can simply use a shell loop to break up the processing into individual mv commands:



          for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done


          This uses only POSIX Shell Command Language features and utilities. This one-liner is clearer with indentation, with unnecessary semicolons removed:



          for x in *; do
          case "$x" in
          *.jpg|*.png|*.bmp)
          ;; # nothing
          *) # catch-all case
          mv -- "$x" target
          ;;
          esac
          done





          share|improve this answer


























          • With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

            – CivFan
            Oct 23 '15 at 20:48













          • @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

            – Kaz
            Oct 23 '15 at 20:51













          • -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

            – CivFan
            Oct 23 '15 at 21:33













          • Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

            – Kaz
            Oct 24 '15 at 0:29














          9












          9








          9







          The operating system's argument passing limit does not apply to expansions which happen within the shell interpreter. So in addition to using xargs or find, we can simply use a shell loop to break up the processing into individual mv commands:



          for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done


          This uses only POSIX Shell Command Language features and utilities. This one-liner is clearer with indentation, with unnecessary semicolons removed:



          for x in *; do
          case "$x" in
          *.jpg|*.png|*.bmp)
          ;; # nothing
          *) # catch-all case
          mv -- "$x" target
          ;;
          esac
          done





          share|improve this answer















          The operating system's argument passing limit does not apply to expansions which happen within the shell interpreter. So in addition to using xargs or find, we can simply use a shell loop to break up the processing into individual mv commands:



          for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done


          This uses only POSIX Shell Command Language features and utilities. This one-liner is clearer with indentation, with unnecessary semicolons removed:



          for x in *; do
          case "$x" in
          *.jpg|*.png|*.bmp)
          ;; # nothing
          *) # catch-all case
          mv -- "$x" target
          ;;
          esac
          done






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 7 '15 at 6:46









          Whitecat

          218112




          218112










          answered Sep 17 '14 at 21:22









          KazKaz

          4,59311432




          4,59311432













          • With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

            – CivFan
            Oct 23 '15 at 20:48













          • @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

            – Kaz
            Oct 23 '15 at 20:51













          • -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

            – CivFan
            Oct 23 '15 at 21:33













          • Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

            – Kaz
            Oct 24 '15 at 0:29



















          • With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

            – CivFan
            Oct 23 '15 at 20:48













          • @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

            – Kaz
            Oct 23 '15 at 20:51













          • -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

            – CivFan
            Oct 23 '15 at 21:33













          • Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

            – Kaz
            Oct 24 '15 at 0:29

















          With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

          – CivFan
          Oct 23 '15 at 20:48







          With more than a million files, this will in turn spawn more than a million mv processes, instead of just the few needed using the POSIX find solution @Gilles posted. In other words, this way results in lots of unnecessary CPU churn.

          – CivFan
          Oct 23 '15 at 20:48















          @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

          – Kaz
          Oct 23 '15 at 20:51







          @CivFan Another problem is convincing yourself that the modified version is equivalent to the original. It's easy to see that the case statement on the result of * expansion to filter out several extensions is equivalent to the original !(*.jpg|*.png|*.bmp) expression. The find answer is in fact not equivalent; it descends into subdirectories (I don't see a -maxdepth predicate).

          – Kaz
          Oct 23 '15 at 20:51















          -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

          – CivFan
          Oct 23 '15 at 21:33







          -name . -o -type d -prune -o protects from descending into sub-directories. -maxdepth is apparently not POSIX compliant, though that's not mentioned in my find man page.

          – CivFan
          Oct 23 '15 at 21:33















          Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

          – Kaz
          Oct 24 '15 at 0:29





          Rolled back to revision 1. The question doesn't say anything about source or destination variables, so this adds unnecessary cruft to the answer.

          – Kaz
          Oct 24 '15 at 0:29











          5














          For a more aggressive solution than those previously offered, pull up your kernel source and edit include/linux/binfmts.h



          Increase the size of MAX_ARG_PAGES to something larger than 32. This increases the amount of memory the kernel will allow for program arguments, thereby allowing you to specify your mv or rm command for a million files or whatever you're doing. Recompile, install, reboot.



          BEWARE! If you set this too large for your system memory, and then run a command with a lot of arguments BAD THINGS WILL HAPPEN! Be extremely cautious doing this to multi-user systems, it makes it easier for malicious users to use up all your memory!



          If you don't know how to recompile and reinstall your kernel manually, it's probably best that you just pretend this answer doesn't exist for now.






          share|improve this answer






























            5














            For a more aggressive solution than those previously offered, pull up your kernel source and edit include/linux/binfmts.h



            Increase the size of MAX_ARG_PAGES to something larger than 32. This increases the amount of memory the kernel will allow for program arguments, thereby allowing you to specify your mv or rm command for a million files or whatever you're doing. Recompile, install, reboot.



            BEWARE! If you set this too large for your system memory, and then run a command with a lot of arguments BAD THINGS WILL HAPPEN! Be extremely cautious doing this to multi-user systems, it makes it easier for malicious users to use up all your memory!



            If you don't know how to recompile and reinstall your kernel manually, it's probably best that you just pretend this answer doesn't exist for now.






            share|improve this answer




























              5












              5








              5







              For a more aggressive solution than those previously offered, pull up your kernel source and edit include/linux/binfmts.h



              Increase the size of MAX_ARG_PAGES to something larger than 32. This increases the amount of memory the kernel will allow for program arguments, thereby allowing you to specify your mv or rm command for a million files or whatever you're doing. Recompile, install, reboot.



              BEWARE! If you set this too large for your system memory, and then run a command with a lot of arguments BAD THINGS WILL HAPPEN! Be extremely cautious doing this to multi-user systems, it makes it easier for malicious users to use up all your memory!



              If you don't know how to recompile and reinstall your kernel manually, it's probably best that you just pretend this answer doesn't exist for now.






              share|improve this answer















              For a more aggressive solution than those previously offered, pull up your kernel source and edit include/linux/binfmts.h



              Increase the size of MAX_ARG_PAGES to something larger than 32. This increases the amount of memory the kernel will allow for program arguments, thereby allowing you to specify your mv or rm command for a million files or whatever you're doing. Recompile, install, reboot.



              BEWARE! If you set this too large for your system memory, and then run a command with a lot of arguments BAD THINGS WILL HAPPEN! Be extremely cautious doing this to multi-user systems, it makes it easier for malicious users to use up all your memory!



              If you don't know how to recompile and reinstall your kernel manually, it's probably best that you just pretend this answer doesn't exist for now.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jun 19 '15 at 21:33









              muru

              1




              1










              answered Jun 19 '15 at 17:26









              PerkinsPerkins

              25525




              25525























                  4














                  A more simple solution using "$origin"/!(*.jpg|*.png|*.bmp) instead of a catch block:





                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done


                  Thanks to @Score_Under



                  For a multi-line script you can do the following (notice the ; before the done is dropped):



                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do        # don't copy types *.jpg|*.png|*.bmp
                  mv -- "$file" "$destination"
                  done


                  To do a more generalized solution that moves all files, you can do the one-liner:



                  for file in "$origin"/*; do mv -- "$file" "$destination" ; done


                  Which looks like this if you do indentation:



                  for file in "$origin"/*; do
                  mv -- "$file" "$destination"
                  done


                  This takes every file in the origin and moves them one by one to the destination. The quotes around $file are necessary in case there are spaces or other special characters in the filenames.



                  Here is an example of this method that worked perfectly



                  for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
                  mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
                  done





                  share|improve this answer


























                  • You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

                    – Score_Under
                    Jun 20 '15 at 0:34











                  • What do you mean original glob?

                    – Whitecat
                    Jun 20 '15 at 0:38











                  • Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

                    – Score_Under
                    Jun 21 '15 at 3:52











                  • Awesome Score. I incorporated your comment and updated my answer.

                    – Whitecat
                    Jun 27 '15 at 22:55
















                  4














                  A more simple solution using "$origin"/!(*.jpg|*.png|*.bmp) instead of a catch block:





                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done


                  Thanks to @Score_Under



                  For a multi-line script you can do the following (notice the ; before the done is dropped):



                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do        # don't copy types *.jpg|*.png|*.bmp
                  mv -- "$file" "$destination"
                  done


                  To do a more generalized solution that moves all files, you can do the one-liner:



                  for file in "$origin"/*; do mv -- "$file" "$destination" ; done


                  Which looks like this if you do indentation:



                  for file in "$origin"/*; do
                  mv -- "$file" "$destination"
                  done


                  This takes every file in the origin and moves them one by one to the destination. The quotes around $file are necessary in case there are spaces or other special characters in the filenames.



                  Here is an example of this method that worked perfectly



                  for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
                  mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
                  done





                  share|improve this answer


























                  • You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

                    – Score_Under
                    Jun 20 '15 at 0:34











                  • What do you mean original glob?

                    – Whitecat
                    Jun 20 '15 at 0:38











                  • Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

                    – Score_Under
                    Jun 21 '15 at 3:52











                  • Awesome Score. I incorporated your comment and updated my answer.

                    – Whitecat
                    Jun 27 '15 at 22:55














                  4












                  4








                  4







                  A more simple solution using "$origin"/!(*.jpg|*.png|*.bmp) instead of a catch block:





                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done


                  Thanks to @Score_Under



                  For a multi-line script you can do the following (notice the ; before the done is dropped):



                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do        # don't copy types *.jpg|*.png|*.bmp
                  mv -- "$file" "$destination"
                  done


                  To do a more generalized solution that moves all files, you can do the one-liner:



                  for file in "$origin"/*; do mv -- "$file" "$destination" ; done


                  Which looks like this if you do indentation:



                  for file in "$origin"/*; do
                  mv -- "$file" "$destination"
                  done


                  This takes every file in the origin and moves them one by one to the destination. The quotes around $file are necessary in case there are spaces or other special characters in the filenames.



                  Here is an example of this method that worked perfectly



                  for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
                  mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
                  done





                  share|improve this answer















                  A more simple solution using "$origin"/!(*.jpg|*.png|*.bmp) instead of a catch block:





                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done


                  Thanks to @Score_Under



                  For a multi-line script you can do the following (notice the ; before the done is dropped):



                  for file in "$origin"/!(*.jpg|*.png|*.bmp); do        # don't copy types *.jpg|*.png|*.bmp
                  mv -- "$file" "$destination"
                  done


                  To do a more generalized solution that moves all files, you can do the one-liner:



                  for file in "$origin"/*; do mv -- "$file" "$destination" ; done


                  Which looks like this if you do indentation:



                  for file in "$origin"/*; do
                  mv -- "$file" "$destination"
                  done


                  This takes every file in the origin and moves them one by one to the destination. The quotes around $file are necessary in case there are spaces or other special characters in the filenames.



                  Here is an example of this method that worked perfectly



                  for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
                  mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
                  done






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jun 15 '17 at 16:52

























                  answered Jun 19 '15 at 21:07









                  WhitecatWhitecat

                  218112




                  218112













                  • You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

                    – Score_Under
                    Jun 20 '15 at 0:34











                  • What do you mean original glob?

                    – Whitecat
                    Jun 20 '15 at 0:38











                  • Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

                    – Score_Under
                    Jun 21 '15 at 3:52











                  • Awesome Score. I incorporated your comment and updated my answer.

                    – Whitecat
                    Jun 27 '15 at 22:55



















                  • You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

                    – Score_Under
                    Jun 20 '15 at 0:34











                  • What do you mean original glob?

                    – Whitecat
                    Jun 20 '15 at 0:38











                  • Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

                    – Score_Under
                    Jun 21 '15 at 3:52











                  • Awesome Score. I incorporated your comment and updated my answer.

                    – Whitecat
                    Jun 27 '15 at 22:55

















                  You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

                  – Score_Under
                  Jun 20 '15 at 0:34





                  You could use something like the original glob in the for-loop to get a closer solution to what's being asked for.

                  – Score_Under
                  Jun 20 '15 at 0:34













                  What do you mean original glob?

                  – Whitecat
                  Jun 20 '15 at 0:38





                  What do you mean original glob?

                  – Whitecat
                  Jun 20 '15 at 0:38













                  Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

                  – Score_Under
                  Jun 21 '15 at 3:52





                  Sorry if that was a little cryptic, I was referring to the glob in the question: !(*.jpg|*.png|*.bmp). You could add that to your for-loop by globbing "$origin"/!(*.jpg|*.png|*.bmp) which would avoid the need for the switch used in Kaz's answer and keep the simple body of the for-loop.

                  – Score_Under
                  Jun 21 '15 at 3:52













                  Awesome Score. I incorporated your comment and updated my answer.

                  – Whitecat
                  Jun 27 '15 at 22:55





                  Awesome Score. I incorporated your comment and updated my answer.

                  – Whitecat
                  Jun 27 '15 at 22:55











                  3














                  If working with Linux kernel is enough you can simply do



                  ulimit -s 100000


                  that will work because Linux kernel included a patch around 10 years ago that changed argument limit to be based on stack size: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba



                  Update: If you feel brave, you can say



                  ulimit -s unlimited


                  and you'll be fine with any shell expansions as long as you have enough RAM.






                  share|improve this answer


























                  • That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

                    – Kusalananda
                    Nov 1 '17 at 9:38











                  • Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

                    – Mikko Rantalainen
                    Nov 3 '17 at 13:00











                  • With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

                    – Mikko Rantalainen
                    Jun 8 '18 at 7:01


















                  3














                  If working with Linux kernel is enough you can simply do



                  ulimit -s 100000


                  that will work because Linux kernel included a patch around 10 years ago that changed argument limit to be based on stack size: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba



                  Update: If you feel brave, you can say



                  ulimit -s unlimited


                  and you'll be fine with any shell expansions as long as you have enough RAM.






                  share|improve this answer


























                  • That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

                    – Kusalananda
                    Nov 1 '17 at 9:38











                  • Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

                    – Mikko Rantalainen
                    Nov 3 '17 at 13:00











                  • With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

                    – Mikko Rantalainen
                    Jun 8 '18 at 7:01
















                  3












                  3








                  3







                  If working with Linux kernel is enough you can simply do



                  ulimit -s 100000


                  that will work because Linux kernel included a patch around 10 years ago that changed argument limit to be based on stack size: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba



                  Update: If you feel brave, you can say



                  ulimit -s unlimited


                  and you'll be fine with any shell expansions as long as you have enough RAM.






                  share|improve this answer















                  If working with Linux kernel is enough you can simply do



                  ulimit -s 100000


                  that will work because Linux kernel included a patch around 10 years ago that changed argument limit to be based on stack size: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba



                  Update: If you feel brave, you can say



                  ulimit -s unlimited


                  and you'll be fine with any shell expansions as long as you have enough RAM.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 3 '17 at 13:04

























                  answered Nov 1 '17 at 9:24









                  Mikko RantalainenMikko Rantalainen

                  1,472815




                  1,472815













                  • That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

                    – Kusalananda
                    Nov 1 '17 at 9:38











                  • Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

                    – Mikko Rantalainen
                    Nov 3 '17 at 13:00











                  • With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

                    – Mikko Rantalainen
                    Jun 8 '18 at 7:01





















                  • That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

                    – Kusalananda
                    Nov 1 '17 at 9:38











                  • Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

                    – Mikko Rantalainen
                    Nov 3 '17 at 13:00











                  • With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

                    – Mikko Rantalainen
                    Jun 8 '18 at 7:01



















                  That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

                  – Kusalananda
                  Nov 1 '17 at 9:38





                  That's a hack. How would you know what to set the stack limit to? This also affects other processes started in the same session.

                  – Kusalananda
                  Nov 1 '17 at 9:38













                  Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

                  – Mikko Rantalainen
                  Nov 3 '17 at 13:00





                  Yeah, it's a hack. Most of the time this kind of hacks are one-off (how often you manually move huge amount of files anyway?). If you are sure that the process is not going to eat all your RAM, you can set ulimit -s unlimited and it will work for practically unlimited files.

                  – Mikko Rantalainen
                  Nov 3 '17 at 13:00













                  With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

                  – Mikko Rantalainen
                  Jun 8 '18 at 7:01







                  With ulimit -s unlimited the actual command line limit is 2^31 or 2 GB. (MAX_ARG_STRLEN in kernel source.)

                  – Mikko Rantalainen
                  Jun 8 '18 at 7:01













                  1














                  You can get around that restriction while still using mv if you don't mind running it a couple times.



                  You can move portions at a time. Let's say for example you had a long list of alphanumeric file names.



                  mv ./subdir/a* ./


                  That works. Then knock out another big chunk. After a couple moves, you can just go back to using mv ./subdir/* ./






                  share|improve this answer




























                    1














                    You can get around that restriction while still using mv if you don't mind running it a couple times.



                    You can move portions at a time. Let's say for example you had a long list of alphanumeric file names.



                    mv ./subdir/a* ./


                    That works. Then knock out another big chunk. After a couple moves, you can just go back to using mv ./subdir/* ./






                    share|improve this answer


























                      1












                      1








                      1







                      You can get around that restriction while still using mv if you don't mind running it a couple times.



                      You can move portions at a time. Let's say for example you had a long list of alphanumeric file names.



                      mv ./subdir/a* ./


                      That works. Then knock out another big chunk. After a couple moves, you can just go back to using mv ./subdir/* ./






                      share|improve this answer













                      You can get around that restriction while still using mv if you don't mind running it a couple times.



                      You can move portions at a time. Let's say for example you had a long list of alphanumeric file names.



                      mv ./subdir/a* ./


                      That works. Then knock out another big chunk. After a couple moves, you can just go back to using mv ./subdir/* ./







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Nov 12 '15 at 2:46









                      KristianKristian

                      1113




                      1113























                          0














                          Sometimes it's easiest to just write a little script, e.g. in Python:



                          import glob, shutil

                          for i in glob.glob('*.jpg'):
                          shutil.move(i, 'new_dir/' + i)





                          share|improve this answer




























                            0














                            Sometimes it's easiest to just write a little script, e.g. in Python:



                            import glob, shutil

                            for i in glob.glob('*.jpg'):
                            shutil.move(i, 'new_dir/' + i)





                            share|improve this answer


























                              0












                              0








                              0







                              Sometimes it's easiest to just write a little script, e.g. in Python:



                              import glob, shutil

                              for i in glob.glob('*.jpg'):
                              shutil.move(i, 'new_dir/' + i)





                              share|improve this answer













                              Sometimes it's easiest to just write a little script, e.g. in Python:



                              import glob, shutil

                              for i in glob.glob('*.jpg'):
                              shutil.move(i, 'new_dir/' + i)






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Oct 10 '18 at 22:22









                              duhaimeduhaime

                              1435




                              1435























                                  0














                                  Here is my two cents, append this into .bash_profile



                                  mv() {
                                  if [[ -d $1 ]]; then #directory mv
                                  /bin/mv $1 $2
                                  elif [[ -f $1 ]]; then #file mv
                                  /bin/mv $1 $2
                                  else
                                  for f in $1
                                  do
                                  source_path=$f
                                  #echo $source_path
                                  source_file=${source_path##*/}
                                  #echo $source_file
                                  destination_path=${2%/} #get rid of trailing forward slash

                                  echo "Moving $f to $destination_path/$source_file"

                                  /bin/mv $f $destination_path/$source_file
                                  done
                                  fi
                                  }
                                  export -f mv


                                  Usage



                                  mv '*.jpg' ./destination/
                                  mv '/path/*' ./destination/




                                  share








                                  New contributor




                                  Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                  Check out our Code of Conduct.

























                                    0














                                    Here is my two cents, append this into .bash_profile



                                    mv() {
                                    if [[ -d $1 ]]; then #directory mv
                                    /bin/mv $1 $2
                                    elif [[ -f $1 ]]; then #file mv
                                    /bin/mv $1 $2
                                    else
                                    for f in $1
                                    do
                                    source_path=$f
                                    #echo $source_path
                                    source_file=${source_path##*/}
                                    #echo $source_file
                                    destination_path=${2%/} #get rid of trailing forward slash

                                    echo "Moving $f to $destination_path/$source_file"

                                    /bin/mv $f $destination_path/$source_file
                                    done
                                    fi
                                    }
                                    export -f mv


                                    Usage



                                    mv '*.jpg' ./destination/
                                    mv '/path/*' ./destination/




                                    share








                                    New contributor




                                    Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.























                                      0












                                      0








                                      0







                                      Here is my two cents, append this into .bash_profile



                                      mv() {
                                      if [[ -d $1 ]]; then #directory mv
                                      /bin/mv $1 $2
                                      elif [[ -f $1 ]]; then #file mv
                                      /bin/mv $1 $2
                                      else
                                      for f in $1
                                      do
                                      source_path=$f
                                      #echo $source_path
                                      source_file=${source_path##*/}
                                      #echo $source_file
                                      destination_path=${2%/} #get rid of trailing forward slash

                                      echo "Moving $f to $destination_path/$source_file"

                                      /bin/mv $f $destination_path/$source_file
                                      done
                                      fi
                                      }
                                      export -f mv


                                      Usage



                                      mv '*.jpg' ./destination/
                                      mv '/path/*' ./destination/




                                      share








                                      New contributor




                                      Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.










                                      Here is my two cents, append this into .bash_profile



                                      mv() {
                                      if [[ -d $1 ]]; then #directory mv
                                      /bin/mv $1 $2
                                      elif [[ -f $1 ]]; then #file mv
                                      /bin/mv $1 $2
                                      else
                                      for f in $1
                                      do
                                      source_path=$f
                                      #echo $source_path
                                      source_file=${source_path##*/}
                                      #echo $source_file
                                      destination_path=${2%/} #get rid of trailing forward slash

                                      echo "Moving $f to $destination_path/$source_file"

                                      /bin/mv $f $destination_path/$source_file
                                      done
                                      fi
                                      }
                                      export -f mv


                                      Usage



                                      mv '*.jpg' ./destination/
                                      mv '/path/*' ./destination/





                                      share








                                      New contributor




                                      Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.








                                      share


                                      share






                                      New contributor




                                      Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.









                                      answered 4 mins ago









                                      AkoAko

                                      1011




                                      1011




                                      New contributor




                                      Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.





                                      New contributor





                                      Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.






                                      Ako is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f128559%2fsolving-mv-argument-list-too-long%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          Accessing regular linux commands in Huawei's Dopra Linux

                                          Can't connect RFCOMM socket: Host is down

                                          Kernel panic - not syncing: Fatal Exception in Interrupt