Set file modification date from date stored as filename

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
0
down vote

favorite












I have a lot of files where filename contains file creation date (IMG_RRRRMMDD_hhmmss.jpg):



IMG_20171015_133516.jpg
IMG_20171015_133827.jpg
IMG_20171015_142634.jpg
IMG_20171015_142834.jpg
IMG_20171015_142857.jpg


but actual file creation date is different. I need to set it back to date from a filename.



I know how to change the date of all files to current date:



find -type f -exec touch ;


and how to parse the file name to get the date in the proper format for touch -t



echo IMG_20171015_133516.jpg | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)'
201710151335.16


But I have no idea how to combine these commands together to change all files.



find -type f -exec touch -t"$(echo '' | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)')" ;


returns




touch: invalid date format ‘.’








share|improve this question


























    up vote
    0
    down vote

    favorite












    I have a lot of files where filename contains file creation date (IMG_RRRRMMDD_hhmmss.jpg):



    IMG_20171015_133516.jpg
    IMG_20171015_133827.jpg
    IMG_20171015_142634.jpg
    IMG_20171015_142834.jpg
    IMG_20171015_142857.jpg


    but actual file creation date is different. I need to set it back to date from a filename.



    I know how to change the date of all files to current date:



    find -type f -exec touch ;


    and how to parse the file name to get the date in the proper format for touch -t



    echo IMG_20171015_133516.jpg | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)'
    201710151335.16


    But I have no idea how to combine these commands together to change all files.



    find -type f -exec touch -t"$(echo '' | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)')" ;


    returns




    touch: invalid date format ‘.’








    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I have a lot of files where filename contains file creation date (IMG_RRRRMMDD_hhmmss.jpg):



      IMG_20171015_133516.jpg
      IMG_20171015_133827.jpg
      IMG_20171015_142634.jpg
      IMG_20171015_142834.jpg
      IMG_20171015_142857.jpg


      but actual file creation date is different. I need to set it back to date from a filename.



      I know how to change the date of all files to current date:



      find -type f -exec touch ;


      and how to parse the file name to get the date in the proper format for touch -t



      echo IMG_20171015_133516.jpg | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)'
      201710151335.16


      But I have no idea how to combine these commands together to change all files.



      find -type f -exec touch -t"$(echo '' | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)')" ;


      returns




      touch: invalid date format ‘.’








      share|improve this question














      I have a lot of files where filename contains file creation date (IMG_RRRRMMDD_hhmmss.jpg):



      IMG_20171015_133516.jpg
      IMG_20171015_133827.jpg
      IMG_20171015_142634.jpg
      IMG_20171015_142834.jpg
      IMG_20171015_142857.jpg


      but actual file creation date is different. I need to set it back to date from a filename.



      I know how to change the date of all files to current date:



      find -type f -exec touch ;


      and how to parse the file name to get the date in the proper format for touch -t



      echo IMG_20171015_133516.jpg | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)'
      201710151335.16


      But I have no idea how to combine these commands together to change all files.



      find -type f -exec touch -t"$(echo '' | awk -F_ 'print $2 substr($3,0,4) "." substr($3,5,2)')" ;


      returns




      touch: invalid date format ‘.’










      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 7 '17 at 20:14









      Jeff Schaller

      32k848109




      32k848109










      asked Dec 7 '17 at 20:01









      mx0

      1837




      1837




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          5
          down vote



          accepted










          In the shell:



          for f in ./IMG_*.jpg ; do 
          t=$f##*/
          touch "$f" -t "$t:4:8$t:13:4.$t:17:2"
          done


          Bash, ksh, zsh etc have the $var:n:m substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.



          Doing it with find needs the shell, too:



          $ find -name "IMG_*.jpg" -exec bash -c '
          for f; do t=$f##*/; touch "$f" -t "$t:4:8$t:13:4.$t:17:2" ; done
          ' sh +


          The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them.
          The construct is here is rather common (at least in unix.SE answers).
          The main part of the loop here is the same as in the first example.




          The find command in your question find .. -exec touch -t"$(...)" ; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The is piped literally to awk, and it just so happens that the awk script only prints a dot.



          If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute ). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.



          In single quotes example:



          $ find -name x -exec echo 'hello $(foo )' ;
          hello $(foo ./x)





          share|improve this answer






















          • Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
            – mx0
            Dec 8 '17 at 15:50










          • @mx0, ah good point, perhaps that should have been elaborated. edited.
            – ilkkachu
            Dec 8 '17 at 16:00










          • Ok, now I get it, Thanks for fast response.
            – mx0
            Dec 8 '17 at 16:10











          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',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          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%2f409564%2fset-file-modification-date-from-date-stored-as-filename%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          5
          down vote



          accepted










          In the shell:



          for f in ./IMG_*.jpg ; do 
          t=$f##*/
          touch "$f" -t "$t:4:8$t:13:4.$t:17:2"
          done


          Bash, ksh, zsh etc have the $var:n:m substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.



          Doing it with find needs the shell, too:



          $ find -name "IMG_*.jpg" -exec bash -c '
          for f; do t=$f##*/; touch "$f" -t "$t:4:8$t:13:4.$t:17:2" ; done
          ' sh +


          The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them.
          The construct is here is rather common (at least in unix.SE answers).
          The main part of the loop here is the same as in the first example.




          The find command in your question find .. -exec touch -t"$(...)" ; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The is piped literally to awk, and it just so happens that the awk script only prints a dot.



          If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute ). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.



          In single quotes example:



          $ find -name x -exec echo 'hello $(foo )' ;
          hello $(foo ./x)





          share|improve this answer






















          • Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
            – mx0
            Dec 8 '17 at 15:50










          • @mx0, ah good point, perhaps that should have been elaborated. edited.
            – ilkkachu
            Dec 8 '17 at 16:00










          • Ok, now I get it, Thanks for fast response.
            – mx0
            Dec 8 '17 at 16:10















          up vote
          5
          down vote



          accepted










          In the shell:



          for f in ./IMG_*.jpg ; do 
          t=$f##*/
          touch "$f" -t "$t:4:8$t:13:4.$t:17:2"
          done


          Bash, ksh, zsh etc have the $var:n:m substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.



          Doing it with find needs the shell, too:



          $ find -name "IMG_*.jpg" -exec bash -c '
          for f; do t=$f##*/; touch "$f" -t "$t:4:8$t:13:4.$t:17:2" ; done
          ' sh +


          The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them.
          The construct is here is rather common (at least in unix.SE answers).
          The main part of the loop here is the same as in the first example.




          The find command in your question find .. -exec touch -t"$(...)" ; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The is piped literally to awk, and it just so happens that the awk script only prints a dot.



          If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute ). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.



          In single quotes example:



          $ find -name x -exec echo 'hello $(foo )' ;
          hello $(foo ./x)





          share|improve this answer






















          • Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
            – mx0
            Dec 8 '17 at 15:50










          • @mx0, ah good point, perhaps that should have been elaborated. edited.
            – ilkkachu
            Dec 8 '17 at 16:00










          • Ok, now I get it, Thanks for fast response.
            – mx0
            Dec 8 '17 at 16:10













          up vote
          5
          down vote



          accepted







          up vote
          5
          down vote



          accepted






          In the shell:



          for f in ./IMG_*.jpg ; do 
          t=$f##*/
          touch "$f" -t "$t:4:8$t:13:4.$t:17:2"
          done


          Bash, ksh, zsh etc have the $var:n:m substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.



          Doing it with find needs the shell, too:



          $ find -name "IMG_*.jpg" -exec bash -c '
          for f; do t=$f##*/; touch "$f" -t "$t:4:8$t:13:4.$t:17:2" ; done
          ' sh +


          The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them.
          The construct is here is rather common (at least in unix.SE answers).
          The main part of the loop here is the same as in the first example.




          The find command in your question find .. -exec touch -t"$(...)" ; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The is piped literally to awk, and it just so happens that the awk script only prints a dot.



          If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute ). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.



          In single quotes example:



          $ find -name x -exec echo 'hello $(foo )' ;
          hello $(foo ./x)





          share|improve this answer














          In the shell:



          for f in ./IMG_*.jpg ; do 
          t=$f##*/
          touch "$f" -t "$t:4:8$t:13:4.$t:17:2"
          done


          Bash, ksh, zsh etc have the $var:n:m substring expansion, and if you need to do it recursively, enable globstar and use **/IMG_*.jpg instead.



          Doing it with find needs the shell, too:



          $ find -name "IMG_*.jpg" -exec bash -c '
          for f; do t=$f##*/; touch "$f" -t "$t:4:8$t:13:4.$t:17:2" ; done
          ' sh +


          The first argument to Bash after the script goes to the $0 variable, which usually contains the shell name. The rest go to the positional parameters $1, $2, etc. and for f or for f in "$@" loops over them.
          The construct is here is rather common (at least in unix.SE answers).
          The main part of the loop here is the same as in the first example.




          The find command in your question find .. -exec touch -t"$(...)" ; doesn't work since the command substitution is in double quotes, so it gets expanded before find runs. The is piped literally to awk, and it just so happens that the awk script only prints a dot.



          If you did put the command substitution in single quotes, it would be passed to touch as-is (find would only substitute ). touch would get the argument -t$(echo ...), dollar signs, parenthesis and all. find doesn't run the command through the shell by itself, we need to explicitly do it, as above.



          In single quotes example:



          $ find -name x -exec echo 'hello $(foo )' ;
          hello $(foo ./x)






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 8 '17 at 15:59

























          answered Dec 7 '17 at 20:16









          ilkkachu

          50.1k676138




          50.1k676138











          • Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
            – mx0
            Dec 8 '17 at 15:50










          • @mx0, ah good point, perhaps that should have been elaborated. edited.
            – ilkkachu
            Dec 8 '17 at 16:00










          • Ok, now I get it, Thanks for fast response.
            – mx0
            Dec 8 '17 at 16:10

















          • Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
            – mx0
            Dec 8 '17 at 15:50










          • @mx0, ah good point, perhaps that should have been elaborated. edited.
            – ilkkachu
            Dec 8 '17 at 16:00










          • Ok, now I get it, Thanks for fast response.
            – mx0
            Dec 8 '17 at 16:10
















          Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
          – mx0
          Dec 8 '17 at 15:50




          Works great, but I still don't know what's wrong with my approach. Why "$()" returns . instead formatted date?
          – mx0
          Dec 8 '17 at 15:50












          @mx0, ah good point, perhaps that should have been elaborated. edited.
          – ilkkachu
          Dec 8 '17 at 16:00




          @mx0, ah good point, perhaps that should have been elaborated. edited.
          – ilkkachu
          Dec 8 '17 at 16:00












          Ok, now I get it, Thanks for fast response.
          – mx0
          Dec 8 '17 at 16:10





          Ok, now I get it, Thanks for fast response.
          – mx0
          Dec 8 '17 at 16:10


















           

          draft saved


          draft discarded















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f409564%2fset-file-modification-date-from-date-stored-as-filename%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Peggy Mitchell

          Palaiologos

          The Forum (Inglewood, California)