Using sed for files in multiple directories












1















I have a bunch of files in multiple directories with incorrect dates on the first line of each file. I am trying to write a script involving sed and a for loop.



Each file is in its own directory that is made up of the correct date. For example a file might be in: ./2014/06/02/record1 and I would like to replace the date on the first line to read '2014/06/02'.



There are a number of files each in their own directory. How do I use sed and a for loop to achieve this?










share|improve this question




















  • 1





    I know there are similar questions but I specifically wanted to focus on the grabbing of part of a directory and using it within a for-loop and inserting into a file.

    – marzo
    Jan 27 at 7:10











  • So the format is fixed. File will be always like 20xx/xx/xx/recordx

    – PRY
    Jan 27 at 7:59













  • It would be clearer if you could draw a directory tree.

    – Niko Gambt
    Jan 27 at 8:37











  • @P_Yadav, yes that is always the format. The first line of every file must match part of the directory it lies in. If a directory is ~/records/2014/07/01 then the first line of the file must read 2014/07/01.

    – marzo
    Jan 29 at 12:11
















1















I have a bunch of files in multiple directories with incorrect dates on the first line of each file. I am trying to write a script involving sed and a for loop.



Each file is in its own directory that is made up of the correct date. For example a file might be in: ./2014/06/02/record1 and I would like to replace the date on the first line to read '2014/06/02'.



There are a number of files each in their own directory. How do I use sed and a for loop to achieve this?










share|improve this question




















  • 1





    I know there are similar questions but I specifically wanted to focus on the grabbing of part of a directory and using it within a for-loop and inserting into a file.

    – marzo
    Jan 27 at 7:10











  • So the format is fixed. File will be always like 20xx/xx/xx/recordx

    – PRY
    Jan 27 at 7:59













  • It would be clearer if you could draw a directory tree.

    – Niko Gambt
    Jan 27 at 8:37











  • @P_Yadav, yes that is always the format. The first line of every file must match part of the directory it lies in. If a directory is ~/records/2014/07/01 then the first line of the file must read 2014/07/01.

    – marzo
    Jan 29 at 12:11














1












1








1


0






I have a bunch of files in multiple directories with incorrect dates on the first line of each file. I am trying to write a script involving sed and a for loop.



Each file is in its own directory that is made up of the correct date. For example a file might be in: ./2014/06/02/record1 and I would like to replace the date on the first line to read '2014/06/02'.



There are a number of files each in their own directory. How do I use sed and a for loop to achieve this?










share|improve this question
















I have a bunch of files in multiple directories with incorrect dates on the first line of each file. I am trying to write a script involving sed and a for loop.



Each file is in its own directory that is made up of the correct date. For example a file might be in: ./2014/06/02/record1 and I would like to replace the date on the first line to read '2014/06/02'.



There are a number of files each in their own directory. How do I use sed and a for loop to achieve this?







sed files






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 27 at 15:22









Jeff Schaller

40.9k1056130




40.9k1056130










asked Jan 27 at 7:07









marzomarzo

82




82








  • 1





    I know there are similar questions but I specifically wanted to focus on the grabbing of part of a directory and using it within a for-loop and inserting into a file.

    – marzo
    Jan 27 at 7:10











  • So the format is fixed. File will be always like 20xx/xx/xx/recordx

    – PRY
    Jan 27 at 7:59













  • It would be clearer if you could draw a directory tree.

    – Niko Gambt
    Jan 27 at 8:37











  • @P_Yadav, yes that is always the format. The first line of every file must match part of the directory it lies in. If a directory is ~/records/2014/07/01 then the first line of the file must read 2014/07/01.

    – marzo
    Jan 29 at 12:11














  • 1





    I know there are similar questions but I specifically wanted to focus on the grabbing of part of a directory and using it within a for-loop and inserting into a file.

    – marzo
    Jan 27 at 7:10











  • So the format is fixed. File will be always like 20xx/xx/xx/recordx

    – PRY
    Jan 27 at 7:59













  • It would be clearer if you could draw a directory tree.

    – Niko Gambt
    Jan 27 at 8:37











  • @P_Yadav, yes that is always the format. The first line of every file must match part of the directory it lies in. If a directory is ~/records/2014/07/01 then the first line of the file must read 2014/07/01.

    – marzo
    Jan 29 at 12:11








1




1





I know there are similar questions but I specifically wanted to focus on the grabbing of part of a directory and using it within a for-loop and inserting into a file.

– marzo
Jan 27 at 7:10





I know there are similar questions but I specifically wanted to focus on the grabbing of part of a directory and using it within a for-loop and inserting into a file.

– marzo
Jan 27 at 7:10













So the format is fixed. File will be always like 20xx/xx/xx/recordx

– PRY
Jan 27 at 7:59







So the format is fixed. File will be always like 20xx/xx/xx/recordx

– PRY
Jan 27 at 7:59















It would be clearer if you could draw a directory tree.

– Niko Gambt
Jan 27 at 8:37





It would be clearer if you could draw a directory tree.

– Niko Gambt
Jan 27 at 8:37













@P_Yadav, yes that is always the format. The first line of every file must match part of the directory it lies in. If a directory is ~/records/2014/07/01 then the first line of the file must read 2014/07/01.

– marzo
Jan 29 at 12:11





@P_Yadav, yes that is always the format. The first line of every file must match part of the directory it lies in. If a directory is ~/records/2014/07/01 then the first line of the file must read 2014/07/01.

– marzo
Jan 29 at 12:11










3 Answers
3






active

oldest

votes


















1














To loop over all the files, assuming you are in the parent directory of e.g. 2014 and that the files themselves are called record<something>:



for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
do
if [ -f "$pathname" ]; then
# ...
fi
done


The pattern 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record* would match all the pathnames that you mention, assuming you only have top-level directories for years 2000 to at most 2099.



The test in the loop is to make sure that the $pathname value is the pathname of an existing regular file (or a symbolic link to one). If the pattern does not match anything, it would by default (in most shells) remain unexpanded. The test would catch this.



To get the directory path for $pathname in the above loop:



dirpath=$( dirname "$pathname" )


or



dirpath=${pathname%/*}


The dirname utility return a string which is the directory path of the given pathname. The variable substitution variation of this removes anything from the last / in $pathname. In this case, either command would generate the same result, but using dirname is generally safer (it would return a given the string a/b/, not a/b which the variable substitution would do).



To replace the first line of the file at $pathname with the string in $dirpath (using GNU sed and in-place editing):



sed -i -e '1c' -e "$dirpath" "$pathname"


The c command in sed would remove the content of a line completely and insert something else in its place. Here, we apply it to only the first line and insert the generated string $dirname, which will be the date from the pathname.



Bringing this together into a script:



#!/bin/sh

for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
do
if [ -f "$pathname" ]; then
dirpath=${pathname%/*}
sed -i -e '1c' -e "$dirpath" "$pathname"
fi
done


Test it on a backup copy of your files.





An equivalent implementation using find instead (mostly equivalent, it will not process record* files that are symbolic links to regular files):



find 20[0-9][0-9]/ -type f 
-path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
for pathname do
sed -i -e "1c\" -e "$( dirname "$pathname" )" "$pathname"
done' sh {} +


This employs basically the same loop as the first variation of the solution.






share|improve this answer


























  • Thank you very much.

    – marzo
    Jan 28 at 2:27



















0














Try this script:



#!/bin/bash

for YEAR in $(ls -1)
do
echo -n Processing year $YEAR " "
for MONTH in $(ls -1 $YEAR)
do
echo -n month $MONTH " "
for DAY in $(ls -1 $YEAR/$MONTH)
do
echo -n day $DAY
sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
done
done
echo " "
done


Note: Save the script in a directory above the tree of files and run it like this:



~/tree-of-files $ ../change-dates.sh 
Processing year 2014 month 06 day 02
Processing year 2017 month 06 day 02
Processing year 2018 month 06 day 02
Processing year 2033 month 06 day 02
~/tree-of-files $





share|improve this answer































    0














    Here's a slight variation on the existing approaches: loop through the files using wildcard patterns that assume a YYYY/MM/DD directory format; on each of those files, use ed to change the first line to be the corresponding name of the containing directory structure:



    for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
    do
    [ -f "$file" ] || continue
    ed -s "$file" <<< $'1cn'"${file%/*}"$'n.nwnq'
    done


    The ed command is given as a here-string with the following components:





    • 1c -- change line 1 to ...


    • ${file%/*} -- the parameter expansion of the file variable that results from removing the last forward slash onwards (keeping only the timestamp/directory structure part)


    • . -- end the change command


    • w -- write the file to disk


    • q -- quit ed






    share|improve this answer























      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%2f496974%2fusing-sed-for-files-in-multiple-directories%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      To loop over all the files, assuming you are in the parent directory of e.g. 2014 and that the files themselves are called record<something>:



      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      # ...
      fi
      done


      The pattern 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record* would match all the pathnames that you mention, assuming you only have top-level directories for years 2000 to at most 2099.



      The test in the loop is to make sure that the $pathname value is the pathname of an existing regular file (or a symbolic link to one). If the pattern does not match anything, it would by default (in most shells) remain unexpanded. The test would catch this.



      To get the directory path for $pathname in the above loop:



      dirpath=$( dirname "$pathname" )


      or



      dirpath=${pathname%/*}


      The dirname utility return a string which is the directory path of the given pathname. The variable substitution variation of this removes anything from the last / in $pathname. In this case, either command would generate the same result, but using dirname is generally safer (it would return a given the string a/b/, not a/b which the variable substitution would do).



      To replace the first line of the file at $pathname with the string in $dirpath (using GNU sed and in-place editing):



      sed -i -e '1c' -e "$dirpath" "$pathname"


      The c command in sed would remove the content of a line completely and insert something else in its place. Here, we apply it to only the first line and insert the generated string $dirname, which will be the date from the pathname.



      Bringing this together into a script:



      #!/bin/sh

      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      dirpath=${pathname%/*}
      sed -i -e '1c' -e "$dirpath" "$pathname"
      fi
      done


      Test it on a backup copy of your files.





      An equivalent implementation using find instead (mostly equivalent, it will not process record* files that are symbolic links to regular files):



      find 20[0-9][0-9]/ -type f 
      -path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
      for pathname do
      sed -i -e "1c\" -e "$( dirname "$pathname" )" "$pathname"
      done' sh {} +


      This employs basically the same loop as the first variation of the solution.






      share|improve this answer


























      • Thank you very much.

        – marzo
        Jan 28 at 2:27
















      1














      To loop over all the files, assuming you are in the parent directory of e.g. 2014 and that the files themselves are called record<something>:



      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      # ...
      fi
      done


      The pattern 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record* would match all the pathnames that you mention, assuming you only have top-level directories for years 2000 to at most 2099.



      The test in the loop is to make sure that the $pathname value is the pathname of an existing regular file (or a symbolic link to one). If the pattern does not match anything, it would by default (in most shells) remain unexpanded. The test would catch this.



      To get the directory path for $pathname in the above loop:



      dirpath=$( dirname "$pathname" )


      or



      dirpath=${pathname%/*}


      The dirname utility return a string which is the directory path of the given pathname. The variable substitution variation of this removes anything from the last / in $pathname. In this case, either command would generate the same result, but using dirname is generally safer (it would return a given the string a/b/, not a/b which the variable substitution would do).



      To replace the first line of the file at $pathname with the string in $dirpath (using GNU sed and in-place editing):



      sed -i -e '1c' -e "$dirpath" "$pathname"


      The c command in sed would remove the content of a line completely and insert something else in its place. Here, we apply it to only the first line and insert the generated string $dirname, which will be the date from the pathname.



      Bringing this together into a script:



      #!/bin/sh

      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      dirpath=${pathname%/*}
      sed -i -e '1c' -e "$dirpath" "$pathname"
      fi
      done


      Test it on a backup copy of your files.





      An equivalent implementation using find instead (mostly equivalent, it will not process record* files that are symbolic links to regular files):



      find 20[0-9][0-9]/ -type f 
      -path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
      for pathname do
      sed -i -e "1c\" -e "$( dirname "$pathname" )" "$pathname"
      done' sh {} +


      This employs basically the same loop as the first variation of the solution.






      share|improve this answer


























      • Thank you very much.

        – marzo
        Jan 28 at 2:27














      1












      1








      1







      To loop over all the files, assuming you are in the parent directory of e.g. 2014 and that the files themselves are called record<something>:



      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      # ...
      fi
      done


      The pattern 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record* would match all the pathnames that you mention, assuming you only have top-level directories for years 2000 to at most 2099.



      The test in the loop is to make sure that the $pathname value is the pathname of an existing regular file (or a symbolic link to one). If the pattern does not match anything, it would by default (in most shells) remain unexpanded. The test would catch this.



      To get the directory path for $pathname in the above loop:



      dirpath=$( dirname "$pathname" )


      or



      dirpath=${pathname%/*}


      The dirname utility return a string which is the directory path of the given pathname. The variable substitution variation of this removes anything from the last / in $pathname. In this case, either command would generate the same result, but using dirname is generally safer (it would return a given the string a/b/, not a/b which the variable substitution would do).



      To replace the first line of the file at $pathname with the string in $dirpath (using GNU sed and in-place editing):



      sed -i -e '1c' -e "$dirpath" "$pathname"


      The c command in sed would remove the content of a line completely and insert something else in its place. Here, we apply it to only the first line and insert the generated string $dirname, which will be the date from the pathname.



      Bringing this together into a script:



      #!/bin/sh

      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      dirpath=${pathname%/*}
      sed -i -e '1c' -e "$dirpath" "$pathname"
      fi
      done


      Test it on a backup copy of your files.





      An equivalent implementation using find instead (mostly equivalent, it will not process record* files that are symbolic links to regular files):



      find 20[0-9][0-9]/ -type f 
      -path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
      for pathname do
      sed -i -e "1c\" -e "$( dirname "$pathname" )" "$pathname"
      done' sh {} +


      This employs basically the same loop as the first variation of the solution.






      share|improve this answer















      To loop over all the files, assuming you are in the parent directory of e.g. 2014 and that the files themselves are called record<something>:



      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      # ...
      fi
      done


      The pattern 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record* would match all the pathnames that you mention, assuming you only have top-level directories for years 2000 to at most 2099.



      The test in the loop is to make sure that the $pathname value is the pathname of an existing regular file (or a symbolic link to one). If the pattern does not match anything, it would by default (in most shells) remain unexpanded. The test would catch this.



      To get the directory path for $pathname in the above loop:



      dirpath=$( dirname "$pathname" )


      or



      dirpath=${pathname%/*}


      The dirname utility return a string which is the directory path of the given pathname. The variable substitution variation of this removes anything from the last / in $pathname. In this case, either command would generate the same result, but using dirname is generally safer (it would return a given the string a/b/, not a/b which the variable substitution would do).



      To replace the first line of the file at $pathname with the string in $dirpath (using GNU sed and in-place editing):



      sed -i -e '1c' -e "$dirpath" "$pathname"


      The c command in sed would remove the content of a line completely and insert something else in its place. Here, we apply it to only the first line and insert the generated string $dirname, which will be the date from the pathname.



      Bringing this together into a script:



      #!/bin/sh

      for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
      do
      if [ -f "$pathname" ]; then
      dirpath=${pathname%/*}
      sed -i -e '1c' -e "$dirpath" "$pathname"
      fi
      done


      Test it on a backup copy of your files.





      An equivalent implementation using find instead (mostly equivalent, it will not process record* files that are symbolic links to regular files):



      find 20[0-9][0-9]/ -type f 
      -path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
      for pathname do
      sed -i -e "1c\" -e "$( dirname "$pathname" )" "$pathname"
      done' sh {} +


      This employs basically the same loop as the first variation of the solution.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Jan 27 at 15:45

























      answered Jan 27 at 8:51









      KusalanandaKusalananda

      128k16241398




      128k16241398













      • Thank you very much.

        – marzo
        Jan 28 at 2:27



















      • Thank you very much.

        – marzo
        Jan 28 at 2:27

















      Thank you very much.

      – marzo
      Jan 28 at 2:27





      Thank you very much.

      – marzo
      Jan 28 at 2:27













      0














      Try this script:



      #!/bin/bash

      for YEAR in $(ls -1)
      do
      echo -n Processing year $YEAR " "
      for MONTH in $(ls -1 $YEAR)
      do
      echo -n month $MONTH " "
      for DAY in $(ls -1 $YEAR/$MONTH)
      do
      echo -n day $DAY
      sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
      done
      done
      echo " "
      done


      Note: Save the script in a directory above the tree of files and run it like this:



      ~/tree-of-files $ ../change-dates.sh 
      Processing year 2014 month 06 day 02
      Processing year 2017 month 06 day 02
      Processing year 2018 month 06 day 02
      Processing year 2033 month 06 day 02
      ~/tree-of-files $





      share|improve this answer




























        0














        Try this script:



        #!/bin/bash

        for YEAR in $(ls -1)
        do
        echo -n Processing year $YEAR " "
        for MONTH in $(ls -1 $YEAR)
        do
        echo -n month $MONTH " "
        for DAY in $(ls -1 $YEAR/$MONTH)
        do
        echo -n day $DAY
        sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
        done
        done
        echo " "
        done


        Note: Save the script in a directory above the tree of files and run it like this:



        ~/tree-of-files $ ../change-dates.sh 
        Processing year 2014 month 06 day 02
        Processing year 2017 month 06 day 02
        Processing year 2018 month 06 day 02
        Processing year 2033 month 06 day 02
        ~/tree-of-files $





        share|improve this answer


























          0












          0








          0







          Try this script:



          #!/bin/bash

          for YEAR in $(ls -1)
          do
          echo -n Processing year $YEAR " "
          for MONTH in $(ls -1 $YEAR)
          do
          echo -n month $MONTH " "
          for DAY in $(ls -1 $YEAR/$MONTH)
          do
          echo -n day $DAY
          sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
          done
          done
          echo " "
          done


          Note: Save the script in a directory above the tree of files and run it like this:



          ~/tree-of-files $ ../change-dates.sh 
          Processing year 2014 month 06 day 02
          Processing year 2017 month 06 day 02
          Processing year 2018 month 06 day 02
          Processing year 2033 month 06 day 02
          ~/tree-of-files $





          share|improve this answer













          Try this script:



          #!/bin/bash

          for YEAR in $(ls -1)
          do
          echo -n Processing year $YEAR " "
          for MONTH in $(ls -1 $YEAR)
          do
          echo -n month $MONTH " "
          for DAY in $(ls -1 $YEAR/$MONTH)
          do
          echo -n day $DAY
          sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
          done
          done
          echo " "
          done


          Note: Save the script in a directory above the tree of files and run it like this:



          ~/tree-of-files $ ../change-dates.sh 
          Processing year 2014 month 06 day 02
          Processing year 2017 month 06 day 02
          Processing year 2018 month 06 day 02
          Processing year 2033 month 06 day 02
          ~/tree-of-files $






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 27 at 8:57









          AAber AAber

          212




          212























              0














              Here's a slight variation on the existing approaches: loop through the files using wildcard patterns that assume a YYYY/MM/DD directory format; on each of those files, use ed to change the first line to be the corresponding name of the containing directory structure:



              for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
              do
              [ -f "$file" ] || continue
              ed -s "$file" <<< $'1cn'"${file%/*}"$'n.nwnq'
              done


              The ed command is given as a here-string with the following components:





              • 1c -- change line 1 to ...


              • ${file%/*} -- the parameter expansion of the file variable that results from removing the last forward slash onwards (keeping only the timestamp/directory structure part)


              • . -- end the change command


              • w -- write the file to disk


              • q -- quit ed






              share|improve this answer




























                0














                Here's a slight variation on the existing approaches: loop through the files using wildcard patterns that assume a YYYY/MM/DD directory format; on each of those files, use ed to change the first line to be the corresponding name of the containing directory structure:



                for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
                do
                [ -f "$file" ] || continue
                ed -s "$file" <<< $'1cn'"${file%/*}"$'n.nwnq'
                done


                The ed command is given as a here-string with the following components:





                • 1c -- change line 1 to ...


                • ${file%/*} -- the parameter expansion of the file variable that results from removing the last forward slash onwards (keeping only the timestamp/directory structure part)


                • . -- end the change command


                • w -- write the file to disk


                • q -- quit ed






                share|improve this answer


























                  0












                  0








                  0







                  Here's a slight variation on the existing approaches: loop through the files using wildcard patterns that assume a YYYY/MM/DD directory format; on each of those files, use ed to change the first line to be the corresponding name of the containing directory structure:



                  for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
                  do
                  [ -f "$file" ] || continue
                  ed -s "$file" <<< $'1cn'"${file%/*}"$'n.nwnq'
                  done


                  The ed command is given as a here-string with the following components:





                  • 1c -- change line 1 to ...


                  • ${file%/*} -- the parameter expansion of the file variable that results from removing the last forward slash onwards (keeping only the timestamp/directory structure part)


                  • . -- end the change command


                  • w -- write the file to disk


                  • q -- quit ed






                  share|improve this answer













                  Here's a slight variation on the existing approaches: loop through the files using wildcard patterns that assume a YYYY/MM/DD directory format; on each of those files, use ed to change the first line to be the corresponding name of the containing directory structure:



                  for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
                  do
                  [ -f "$file" ] || continue
                  ed -s "$file" <<< $'1cn'"${file%/*}"$'n.nwnq'
                  done


                  The ed command is given as a here-string with the following components:





                  • 1c -- change line 1 to ...


                  • ${file%/*} -- the parameter expansion of the file variable that results from removing the last forward slash onwards (keeping only the timestamp/directory structure part)


                  • . -- end the change command


                  • w -- write the file to disk


                  • q -- quit ed







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 28 at 1:42









                  Jeff SchallerJeff Schaller

                  40.9k1056130




                  40.9k1056130






























                      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%2f496974%2fusing-sed-for-files-in-multiple-directories%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

                      How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

                      is 'sed' thread safe

                      How to make a Squid Proxy server?