Create directories with a name from txt file which contain '/' character

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








up vote
9
down vote

favorite
2












I have a .txt file that contains a text like this



A1/B1/C1
A2/B2/C2
A3/B3/C3


I want a script that reads the .txt file for each line then create a directory based on the first word (A1, A2, A3)



I have created script like this:



file="test.txt"
while IFS='' read -r line
do
name="line"
mkdir -p $line
done <"$file"


While I run it, it creates directory A1 then it also create sub-directories B1 and C1. the same happens for another line (A2* and A3*)



What should I do to create only A1, A2, A3 directories?



I don't want to make the name like A1/B1/C1 with '/' character in it.
I just want to take the word before '/' character and make it directory name.
Just "A1" "A2" "A3".







share|improve this question


























    up vote
    9
    down vote

    favorite
    2












    I have a .txt file that contains a text like this



    A1/B1/C1
    A2/B2/C2
    A3/B3/C3


    I want a script that reads the .txt file for each line then create a directory based on the first word (A1, A2, A3)



    I have created script like this:



    file="test.txt"
    while IFS='' read -r line
    do
    name="line"
    mkdir -p $line
    done <"$file"


    While I run it, it creates directory A1 then it also create sub-directories B1 and C1. the same happens for another line (A2* and A3*)



    What should I do to create only A1, A2, A3 directories?



    I don't want to make the name like A1/B1/C1 with '/' character in it.
    I just want to take the word before '/' character and make it directory name.
    Just "A1" "A2" "A3".







    share|improve this question
























      up vote
      9
      down vote

      favorite
      2









      up vote
      9
      down vote

      favorite
      2






      2





      I have a .txt file that contains a text like this



      A1/B1/C1
      A2/B2/C2
      A3/B3/C3


      I want a script that reads the .txt file for each line then create a directory based on the first word (A1, A2, A3)



      I have created script like this:



      file="test.txt"
      while IFS='' read -r line
      do
      name="line"
      mkdir -p $line
      done <"$file"


      While I run it, it creates directory A1 then it also create sub-directories B1 and C1. the same happens for another line (A2* and A3*)



      What should I do to create only A1, A2, A3 directories?



      I don't want to make the name like A1/B1/C1 with '/' character in it.
      I just want to take the word before '/' character and make it directory name.
      Just "A1" "A2" "A3".







      share|improve this question














      I have a .txt file that contains a text like this



      A1/B1/C1
      A2/B2/C2
      A3/B3/C3


      I want a script that reads the .txt file for each line then create a directory based on the first word (A1, A2, A3)



      I have created script like this:



      file="test.txt"
      while IFS='' read -r line
      do
      name="line"
      mkdir -p $line
      done <"$file"


      While I run it, it creates directory A1 then it also create sub-directories B1 and C1. the same happens for another line (A2* and A3*)



      What should I do to create only A1, A2, A3 directories?



      I don't want to make the name like A1/B1/C1 with '/' character in it.
      I just want to take the word before '/' character and make it directory name.
      Just "A1" "A2" "A3".









      share|improve this question













      share|improve this question




      share|improve this question








      edited May 25 at 14:59









      αғsнιη

      22.9k2191150




      22.9k2191150










      asked May 24 at 4:36









      maulana

      585




      585




















          6 Answers
          6






          active

          oldest

          votes

















          up vote
          13
          down vote



          accepted












          You can just cut the 1st slash-delimited field of each line and give the list to mkdir:



          mkdir $(<dirlist.txt cut -d/ -f1)


          Example run



          $ cat dirlist.txt 
          A1/A2/A3
          B1/B2/B3
          C1/C2/C3
          $ ls
          dirlist.txt
          $ mkdir $(<dirlist.txt cut -d/ -f1)
          $ ls
          A1 B1 C1 dirlist.txt


          You may run into ARG_MAX problems if your list holds a huge number of directory names, in this case use GNU parallel Install parallel or xargs as follows:



          parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
          xargs -a<(<dirlist.txt cut -d/ -f1) mkdir


          While parallel has it covered, the xargs approach won’t work if the directory names contain spaces – you can either use as the line delimiter or simply instruct xargs to only split the input on newline characters (as proposed by Martin Bonner) instead:



          xargs -0a<(<dirlist.txt tr \n,0 | cut -d/ -f1 -z) mkdir # \n,0 equals \n \0
          xargs -d\n -a<(<dirlist.txt cut -d/ -f1) mkdir


          In case any of the fields contains a newline character one would need to identify the “true” line endings and replace only those newline characters with e.g. . That would be a case for awk, but I feel it’s too far fetched here.






          share|improve this answer






















          • Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
            – Martin Bonner
            May 24 at 16:25






          • 1




            @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
            – dessert
            May 24 at 20:48










          • @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
            – dessert
            May 24 at 20:51










          • @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
            – dessert
            May 24 at 20:55










          • @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
            – dessert
            May 24 at 21:06

















          up vote
          10
          down vote













          You need to set your IFS='/' for read and then assign each first field into separate variable first and the rest of the fields into variable rest and just work on first field's value (Or you can read -ar array to a single array and use "$array[0]" for the first field's value. ):



          while IFS='/' read -r first rest;
          do
          echo mkdir "$first"
          done < test.txt


          Or in single line for those who like it:



          <test.txt xargs -d'n' -n1 sh -c 'echo mkdir "$'1%%/*'"' _


          Or create all directories in one-go:



          <test.txt xargs -d'n' bash -c 'echo mkdir "$'@%%/*'"' _


          The ANSI-C Quoting $'...' is used to deal with directory names containing special characters.



          Note that the _ (can be any character or string) at the end will be argv[0] to the bash -c '...' and the $@ will contains rest of the parameters starting from 1; without that in second command the first parameter to the mkdir will be lost.



          In $1%%/* using shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion, removes longest possible match of a slash followed by anything till the end of the parameter passing into it which is a line that read by xargs;



          P.s:



          • Remove echo in front of the mkdir to create those directories.

          • Replace -d'n' with -0 if your list is separated with NUL characters instead of a newline (supposed there are newline in your directory name and of course there should not be a directory name with NUL characters either).





          share|improve this answer





























            up vote
            6
            down vote













            Contents of test.txt:



            A 12"x4" dir/B b/C c
            A1/B1/C1
            A2/B2/C2
            A3/B3/C3


            Script to create A[123] folders:



            file="test.txt"
            while read -r line ; do
            mkdir "$line%%/*"
            done < "$file"


            Output of ls:



            A 12"x4" dir
            A1
            A2
            A3





            share|improve this answer






















            • How do you deal with input like: A 12"x4" dir/B b/C c?
              – Ole Tange
              May 25 at 11:32










            • Ole Tange - That comment seems completely out of scope for the question.
              – DocSalvager
              May 31 at 4:13

















            up vote
            5
            down vote













            For simple case as shown in the question's input example, just use cut and pass output to mkdir via xargs



            cut -f1 -d '/' file.txt | xargs -L1 mkdir 


            For handling cases where directory name may contain spaces, we could add -d 'n' to the list of options:



            $ cat input.txt 
            A 1/B 1/C 1
            A 2/B 2/C 2
            A 3/B 2/C 2
            $ cut -f1 -d '/' input.txt | xargs -d 'n' mkdir
            $ ls
            A 1 A 2 A 3 input.txt


            For more complex variations, such as A 12"x4" dir/B b/C c as suggested by @OleTange in the comments, one may turn to awk to create null-separated list instead of newline-separated list.



            awk -F'/' 'printf "%s",$1' input.txt | xargs -0 mkdir



            @dessert in the comments wondered whether printf can be used instead of cut , and technically speaking it can be used, for instance via limiting the printed string to the width of 3 characters only:



            xargs -d 'n' printf "%.3sn" < input.txt | xargs -L1 mkdir 


            Not the cleanest way, but it proves printf can be used. Of course, this gets problematic if directory name becomes longer than 3 characters.






            share|improve this answer






















            • How do you deal with input like: A 12"x4" dir/B b/C c?
              – Ole Tange
              May 25 at 11:32










            • @OleTange See the edit.
              – Sergiy Kolodyazhnyy
              May 25 at 14:54

















            up vote
            2
            down vote













            using Perl:



            perl -ne 'mkdir for /^(w+)/' list.txt


            Or



            perl -ne 'mkdir for /^([^/]+)/' list.txt


            if we want to accept spaces on dir-names






            share|improve this answer


















            • 1




              perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
              – dessert
              May 24 at 21:03

















            up vote
            0
            down vote













            GNU Parallel may be overkill for the task, but if you are going to do other stuff for each line, then it may be useful:



            cat myfile.txt | parallel --colsep / mkdir 1
            parallel -a myfile.txt --colsep / mkdir 1


            It deals correctly with input like:



            A 12"x4" dir/B b/C c





            share|improve this answer






















              Your Answer







              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "89"
              ;
              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: true,
              noModals: false,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              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%2faskubuntu.com%2fquestions%2f1039649%2fcreate-directories-with-a-name-from-txt-file-which-contain-character%23new-answer', 'question_page');

              );

              Post as a guest






























              6 Answers
              6






              active

              oldest

              votes








              6 Answers
              6






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              13
              down vote



              accepted












              You can just cut the 1st slash-delimited field of each line and give the list to mkdir:



              mkdir $(<dirlist.txt cut -d/ -f1)


              Example run



              $ cat dirlist.txt 
              A1/A2/A3
              B1/B2/B3
              C1/C2/C3
              $ ls
              dirlist.txt
              $ mkdir $(<dirlist.txt cut -d/ -f1)
              $ ls
              A1 B1 C1 dirlist.txt


              You may run into ARG_MAX problems if your list holds a huge number of directory names, in this case use GNU parallel Install parallel or xargs as follows:



              parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
              xargs -a<(<dirlist.txt cut -d/ -f1) mkdir


              While parallel has it covered, the xargs approach won’t work if the directory names contain spaces – you can either use as the line delimiter or simply instruct xargs to only split the input on newline characters (as proposed by Martin Bonner) instead:



              xargs -0a<(<dirlist.txt tr \n,0 | cut -d/ -f1 -z) mkdir # \n,0 equals \n \0
              xargs -d\n -a<(<dirlist.txt cut -d/ -f1) mkdir


              In case any of the fields contains a newline character one would need to identify the “true” line endings and replace only those newline characters with e.g. . That would be a case for awk, but I feel it’s too far fetched here.






              share|improve this answer






















              • Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
                – Martin Bonner
                May 24 at 16:25






              • 1




                @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
                – dessert
                May 24 at 20:48










              • @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
                – dessert
                May 24 at 20:51










              • @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
                – dessert
                May 24 at 20:55










              • @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
                – dessert
                May 24 at 21:06














              up vote
              13
              down vote



              accepted












              You can just cut the 1st slash-delimited field of each line and give the list to mkdir:



              mkdir $(<dirlist.txt cut -d/ -f1)


              Example run



              $ cat dirlist.txt 
              A1/A2/A3
              B1/B2/B3
              C1/C2/C3
              $ ls
              dirlist.txt
              $ mkdir $(<dirlist.txt cut -d/ -f1)
              $ ls
              A1 B1 C1 dirlist.txt


              You may run into ARG_MAX problems if your list holds a huge number of directory names, in this case use GNU parallel Install parallel or xargs as follows:



              parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
              xargs -a<(<dirlist.txt cut -d/ -f1) mkdir


              While parallel has it covered, the xargs approach won’t work if the directory names contain spaces – you can either use as the line delimiter or simply instruct xargs to only split the input on newline characters (as proposed by Martin Bonner) instead:



              xargs -0a<(<dirlist.txt tr \n,0 | cut -d/ -f1 -z) mkdir # \n,0 equals \n \0
              xargs -d\n -a<(<dirlist.txt cut -d/ -f1) mkdir


              In case any of the fields contains a newline character one would need to identify the “true” line endings and replace only those newline characters with e.g. . That would be a case for awk, but I feel it’s too far fetched here.






              share|improve this answer






















              • Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
                – Martin Bonner
                May 24 at 16:25






              • 1




                @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
                – dessert
                May 24 at 20:48










              • @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
                – dessert
                May 24 at 20:51










              • @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
                – dessert
                May 24 at 20:55










              • @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
                – dessert
                May 24 at 21:06












              up vote
              13
              down vote



              accepted







              up vote
              13
              down vote



              accepted








              You can just cut the 1st slash-delimited field of each line and give the list to mkdir:



              mkdir $(<dirlist.txt cut -d/ -f1)


              Example run



              $ cat dirlist.txt 
              A1/A2/A3
              B1/B2/B3
              C1/C2/C3
              $ ls
              dirlist.txt
              $ mkdir $(<dirlist.txt cut -d/ -f1)
              $ ls
              A1 B1 C1 dirlist.txt


              You may run into ARG_MAX problems if your list holds a huge number of directory names, in this case use GNU parallel Install parallel or xargs as follows:



              parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
              xargs -a<(<dirlist.txt cut -d/ -f1) mkdir


              While parallel has it covered, the xargs approach won’t work if the directory names contain spaces – you can either use as the line delimiter or simply instruct xargs to only split the input on newline characters (as proposed by Martin Bonner) instead:



              xargs -0a<(<dirlist.txt tr \n,0 | cut -d/ -f1 -z) mkdir # \n,0 equals \n \0
              xargs -d\n -a<(<dirlist.txt cut -d/ -f1) mkdir


              In case any of the fields contains a newline character one would need to identify the “true” line endings and replace only those newline characters with e.g. . That would be a case for awk, but I feel it’s too far fetched here.






              share|improve this answer
















              You can just cut the 1st slash-delimited field of each line and give the list to mkdir:



              mkdir $(<dirlist.txt cut -d/ -f1)


              Example run



              $ cat dirlist.txt 
              A1/A2/A3
              B1/B2/B3
              C1/C2/C3
              $ ls
              dirlist.txt
              $ mkdir $(<dirlist.txt cut -d/ -f1)
              $ ls
              A1 B1 C1 dirlist.txt


              You may run into ARG_MAX problems if your list holds a huge number of directory names, in this case use GNU parallel Install parallel or xargs as follows:



              parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
              xargs -a<(<dirlist.txt cut -d/ -f1) mkdir


              While parallel has it covered, the xargs approach won’t work if the directory names contain spaces – you can either use as the line delimiter or simply instruct xargs to only split the input on newline characters (as proposed by Martin Bonner) instead:



              xargs -0a<(<dirlist.txt tr \n,0 | cut -d/ -f1 -z) mkdir # \n,0 equals \n \0
              xargs -d\n -a<(<dirlist.txt cut -d/ -f1) mkdir


              In case any of the fields contains a newline character one would need to identify the “true” line endings and replace only those newline characters with e.g. . That would be a case for awk, but I feel it’s too far fetched here.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited May 25 at 11:38

























              answered May 24 at 5:37









              dessert

              19.5k55594




              19.5k55594











              • Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
                – Martin Bonner
                May 24 at 16:25






              • 1




                @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
                – dessert
                May 24 at 20:48










              • @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
                – dessert
                May 24 at 20:51










              • @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
                – dessert
                May 24 at 20:55










              • @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
                – dessert
                May 24 at 21:06
















              • Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
                – Martin Bonner
                May 24 at 16:25






              • 1




                @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
                – dessert
                May 24 at 20:48










              • @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
                – dessert
                May 24 at 20:51










              • @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
                – dessert
                May 24 at 20:55










              • @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
                – dessert
                May 24 at 21:06















              Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
              – Martin Bonner
              May 24 at 16:25




              Why xargs -a<(....) rather than <dirlist.txt cut -d/ -f1 | xargs?
              – Martin Bonner
              May 24 at 16:25




              1




              1




              @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
              – dessert
              May 24 at 20:48




              @MartinBonner Thanks for clarifying, that’s indeed simpler than my tr approach – just realized that parallel has it covered by default.
              – dessert
              May 24 at 20:48












              @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
              – dessert
              May 24 at 20:51




              @MartinBonner Why xargs -a<(....) rather than a pipe – because I like it this way, as simple as that. :)
              – dessert
              May 24 at 20:51












              @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
              – dessert
              May 24 at 20:55




              @AndreaCorbellini Oh, now I understand. <(...) helps with spaces as well, so it’s definitely the better choice – I don’t think anybody was using this file descriptor anyway.
              – dessert
              May 24 at 20:55












              @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
              – dessert
              May 24 at 21:06




              @MartinBonner More interestingly: Why cut <dirlist.txt instead of just cut dirlist.txt?
              – dessert
              May 24 at 21:06












              up vote
              10
              down vote













              You need to set your IFS='/' for read and then assign each first field into separate variable first and the rest of the fields into variable rest and just work on first field's value (Or you can read -ar array to a single array and use "$array[0]" for the first field's value. ):



              while IFS='/' read -r first rest;
              do
              echo mkdir "$first"
              done < test.txt


              Or in single line for those who like it:



              <test.txt xargs -d'n' -n1 sh -c 'echo mkdir "$'1%%/*'"' _


              Or create all directories in one-go:



              <test.txt xargs -d'n' bash -c 'echo mkdir "$'@%%/*'"' _


              The ANSI-C Quoting $'...' is used to deal with directory names containing special characters.



              Note that the _ (can be any character or string) at the end will be argv[0] to the bash -c '...' and the $@ will contains rest of the parameters starting from 1; without that in second command the first parameter to the mkdir will be lost.



              In $1%%/* using shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion, removes longest possible match of a slash followed by anything till the end of the parameter passing into it which is a line that read by xargs;



              P.s:



              • Remove echo in front of the mkdir to create those directories.

              • Replace -d'n' with -0 if your list is separated with NUL characters instead of a newline (supposed there are newline in your directory name and of course there should not be a directory name with NUL characters either).





              share|improve this answer


























                up vote
                10
                down vote













                You need to set your IFS='/' for read and then assign each first field into separate variable first and the rest of the fields into variable rest and just work on first field's value (Or you can read -ar array to a single array and use "$array[0]" for the first field's value. ):



                while IFS='/' read -r first rest;
                do
                echo mkdir "$first"
                done < test.txt


                Or in single line for those who like it:



                <test.txt xargs -d'n' -n1 sh -c 'echo mkdir "$'1%%/*'"' _


                Or create all directories in one-go:



                <test.txt xargs -d'n' bash -c 'echo mkdir "$'@%%/*'"' _


                The ANSI-C Quoting $'...' is used to deal with directory names containing special characters.



                Note that the _ (can be any character or string) at the end will be argv[0] to the bash -c '...' and the $@ will contains rest of the parameters starting from 1; without that in second command the first parameter to the mkdir will be lost.



                In $1%%/* using shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion, removes longest possible match of a slash followed by anything till the end of the parameter passing into it which is a line that read by xargs;



                P.s:



                • Remove echo in front of the mkdir to create those directories.

                • Replace -d'n' with -0 if your list is separated with NUL characters instead of a newline (supposed there are newline in your directory name and of course there should not be a directory name with NUL characters either).





                share|improve this answer
























                  up vote
                  10
                  down vote










                  up vote
                  10
                  down vote









                  You need to set your IFS='/' for read and then assign each first field into separate variable first and the rest of the fields into variable rest and just work on first field's value (Or you can read -ar array to a single array and use "$array[0]" for the first field's value. ):



                  while IFS='/' read -r first rest;
                  do
                  echo mkdir "$first"
                  done < test.txt


                  Or in single line for those who like it:



                  <test.txt xargs -d'n' -n1 sh -c 'echo mkdir "$'1%%/*'"' _


                  Or create all directories in one-go:



                  <test.txt xargs -d'n' bash -c 'echo mkdir "$'@%%/*'"' _


                  The ANSI-C Quoting $'...' is used to deal with directory names containing special characters.



                  Note that the _ (can be any character or string) at the end will be argv[0] to the bash -c '...' and the $@ will contains rest of the parameters starting from 1; without that in second command the first parameter to the mkdir will be lost.



                  In $1%%/* using shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion, removes longest possible match of a slash followed by anything till the end of the parameter passing into it which is a line that read by xargs;



                  P.s:



                  • Remove echo in front of the mkdir to create those directories.

                  • Replace -d'n' with -0 if your list is separated with NUL characters instead of a newline (supposed there are newline in your directory name and of course there should not be a directory name with NUL characters either).





                  share|improve this answer














                  You need to set your IFS='/' for read and then assign each first field into separate variable first and the rest of the fields into variable rest and just work on first field's value (Or you can read -ar array to a single array and use "$array[0]" for the first field's value. ):



                  while IFS='/' read -r first rest;
                  do
                  echo mkdir "$first"
                  done < test.txt


                  Or in single line for those who like it:



                  <test.txt xargs -d'n' -n1 sh -c 'echo mkdir "$'1%%/*'"' _


                  Or create all directories in one-go:



                  <test.txt xargs -d'n' bash -c 'echo mkdir "$'@%%/*'"' _


                  The ANSI-C Quoting $'...' is used to deal with directory names containing special characters.



                  Note that the _ (can be any character or string) at the end will be argv[0] to the bash -c '...' and the $@ will contains rest of the parameters starting from 1; without that in second command the first parameter to the mkdir will be lost.



                  In $1%%/* using shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion, removes longest possible match of a slash followed by anything till the end of the parameter passing into it which is a line that read by xargs;



                  P.s:



                  • Remove echo in front of the mkdir to create those directories.

                  • Replace -d'n' with -0 if your list is separated with NUL characters instead of a newline (supposed there are newline in your directory name and of course there should not be a directory name with NUL characters either).






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jun 5 at 2:57

























                  answered May 24 at 4:54









                  αғsнιη

                  22.9k2191150




                  22.9k2191150




















                      up vote
                      6
                      down vote













                      Contents of test.txt:



                      A 12"x4" dir/B b/C c
                      A1/B1/C1
                      A2/B2/C2
                      A3/B3/C3


                      Script to create A[123] folders:



                      file="test.txt"
                      while read -r line ; do
                      mkdir "$line%%/*"
                      done < "$file"


                      Output of ls:



                      A 12"x4" dir
                      A1
                      A2
                      A3





                      share|improve this answer






















                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • Ole Tange - That comment seems completely out of scope for the question.
                        – DocSalvager
                        May 31 at 4:13














                      up vote
                      6
                      down vote













                      Contents of test.txt:



                      A 12"x4" dir/B b/C c
                      A1/B1/C1
                      A2/B2/C2
                      A3/B3/C3


                      Script to create A[123] folders:



                      file="test.txt"
                      while read -r line ; do
                      mkdir "$line%%/*"
                      done < "$file"


                      Output of ls:



                      A 12"x4" dir
                      A1
                      A2
                      A3





                      share|improve this answer






















                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • Ole Tange - That comment seems completely out of scope for the question.
                        – DocSalvager
                        May 31 at 4:13












                      up vote
                      6
                      down vote










                      up vote
                      6
                      down vote









                      Contents of test.txt:



                      A 12"x4" dir/B b/C c
                      A1/B1/C1
                      A2/B2/C2
                      A3/B3/C3


                      Script to create A[123] folders:



                      file="test.txt"
                      while read -r line ; do
                      mkdir "$line%%/*"
                      done < "$file"


                      Output of ls:



                      A 12"x4" dir
                      A1
                      A2
                      A3





                      share|improve this answer














                      Contents of test.txt:



                      A 12"x4" dir/B b/C c
                      A1/B1/C1
                      A2/B2/C2
                      A3/B3/C3


                      Script to create A[123] folders:



                      file="test.txt"
                      while read -r line ; do
                      mkdir "$line%%/*"
                      done < "$file"


                      Output of ls:



                      A 12"x4" dir
                      A1
                      A2
                      A3






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 25 at 11:55

























                      answered May 24 at 4:55









                      xiota

                      1,0461421




                      1,0461421











                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • Ole Tange - That comment seems completely out of scope for the question.
                        – DocSalvager
                        May 31 at 4:13
















                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • Ole Tange - That comment seems completely out of scope for the question.
                        – DocSalvager
                        May 31 at 4:13















                      How do you deal with input like: A 12"x4" dir/B b/C c?
                      – Ole Tange
                      May 25 at 11:32




                      How do you deal with input like: A 12"x4" dir/B b/C c?
                      – Ole Tange
                      May 25 at 11:32












                      Ole Tange - That comment seems completely out of scope for the question.
                      – DocSalvager
                      May 31 at 4:13




                      Ole Tange - That comment seems completely out of scope for the question.
                      – DocSalvager
                      May 31 at 4:13










                      up vote
                      5
                      down vote













                      For simple case as shown in the question's input example, just use cut and pass output to mkdir via xargs



                      cut -f1 -d '/' file.txt | xargs -L1 mkdir 


                      For handling cases where directory name may contain spaces, we could add -d 'n' to the list of options:



                      $ cat input.txt 
                      A 1/B 1/C 1
                      A 2/B 2/C 2
                      A 3/B 2/C 2
                      $ cut -f1 -d '/' input.txt | xargs -d 'n' mkdir
                      $ ls
                      A 1 A 2 A 3 input.txt


                      For more complex variations, such as A 12"x4" dir/B b/C c as suggested by @OleTange in the comments, one may turn to awk to create null-separated list instead of newline-separated list.



                      awk -F'/' 'printf "%s",$1' input.txt | xargs -0 mkdir



                      @dessert in the comments wondered whether printf can be used instead of cut , and technically speaking it can be used, for instance via limiting the printed string to the width of 3 characters only:



                      xargs -d 'n' printf "%.3sn" < input.txt | xargs -L1 mkdir 


                      Not the cleanest way, but it proves printf can be used. Of course, this gets problematic if directory name becomes longer than 3 characters.






                      share|improve this answer






















                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • @OleTange See the edit.
                        – Sergiy Kolodyazhnyy
                        May 25 at 14:54














                      up vote
                      5
                      down vote













                      For simple case as shown in the question's input example, just use cut and pass output to mkdir via xargs



                      cut -f1 -d '/' file.txt | xargs -L1 mkdir 


                      For handling cases where directory name may contain spaces, we could add -d 'n' to the list of options:



                      $ cat input.txt 
                      A 1/B 1/C 1
                      A 2/B 2/C 2
                      A 3/B 2/C 2
                      $ cut -f1 -d '/' input.txt | xargs -d 'n' mkdir
                      $ ls
                      A 1 A 2 A 3 input.txt


                      For more complex variations, such as A 12"x4" dir/B b/C c as suggested by @OleTange in the comments, one may turn to awk to create null-separated list instead of newline-separated list.



                      awk -F'/' 'printf "%s",$1' input.txt | xargs -0 mkdir



                      @dessert in the comments wondered whether printf can be used instead of cut , and technically speaking it can be used, for instance via limiting the printed string to the width of 3 characters only:



                      xargs -d 'n' printf "%.3sn" < input.txt | xargs -L1 mkdir 


                      Not the cleanest way, but it proves printf can be used. Of course, this gets problematic if directory name becomes longer than 3 characters.






                      share|improve this answer






















                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • @OleTange See the edit.
                        – Sergiy Kolodyazhnyy
                        May 25 at 14:54












                      up vote
                      5
                      down vote










                      up vote
                      5
                      down vote









                      For simple case as shown in the question's input example, just use cut and pass output to mkdir via xargs



                      cut -f1 -d '/' file.txt | xargs -L1 mkdir 


                      For handling cases where directory name may contain spaces, we could add -d 'n' to the list of options:



                      $ cat input.txt 
                      A 1/B 1/C 1
                      A 2/B 2/C 2
                      A 3/B 2/C 2
                      $ cut -f1 -d '/' input.txt | xargs -d 'n' mkdir
                      $ ls
                      A 1 A 2 A 3 input.txt


                      For more complex variations, such as A 12"x4" dir/B b/C c as suggested by @OleTange in the comments, one may turn to awk to create null-separated list instead of newline-separated list.



                      awk -F'/' 'printf "%s",$1' input.txt | xargs -0 mkdir



                      @dessert in the comments wondered whether printf can be used instead of cut , and technically speaking it can be used, for instance via limiting the printed string to the width of 3 characters only:



                      xargs -d 'n' printf "%.3sn" < input.txt | xargs -L1 mkdir 


                      Not the cleanest way, but it proves printf can be used. Of course, this gets problematic if directory name becomes longer than 3 characters.






                      share|improve this answer














                      For simple case as shown in the question's input example, just use cut and pass output to mkdir via xargs



                      cut -f1 -d '/' file.txt | xargs -L1 mkdir 


                      For handling cases where directory name may contain spaces, we could add -d 'n' to the list of options:



                      $ cat input.txt 
                      A 1/B 1/C 1
                      A 2/B 2/C 2
                      A 3/B 2/C 2
                      $ cut -f1 -d '/' input.txt | xargs -d 'n' mkdir
                      $ ls
                      A 1 A 2 A 3 input.txt


                      For more complex variations, such as A 12"x4" dir/B b/C c as suggested by @OleTange in the comments, one may turn to awk to create null-separated list instead of newline-separated list.



                      awk -F'/' 'printf "%s",$1' input.txt | xargs -0 mkdir



                      @dessert in the comments wondered whether printf can be used instead of cut , and technically speaking it can be used, for instance via limiting the printed string to the width of 3 characters only:



                      xargs -d 'n' printf "%.3sn" < input.txt | xargs -L1 mkdir 


                      Not the cleanest way, but it proves printf can be used. Of course, this gets problematic if directory name becomes longer than 3 characters.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 25 at 14:54

























                      answered May 24 at 5:32









                      Sergiy Kolodyazhnyy

                      64k9127274




                      64k9127274











                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • @OleTange See the edit.
                        – Sergiy Kolodyazhnyy
                        May 25 at 14:54
















                      • How do you deal with input like: A 12"x4" dir/B b/C c?
                        – Ole Tange
                        May 25 at 11:32










                      • @OleTange See the edit.
                        – Sergiy Kolodyazhnyy
                        May 25 at 14:54















                      How do you deal with input like: A 12"x4" dir/B b/C c?
                      – Ole Tange
                      May 25 at 11:32




                      How do you deal with input like: A 12"x4" dir/B b/C c?
                      – Ole Tange
                      May 25 at 11:32












                      @OleTange See the edit.
                      – Sergiy Kolodyazhnyy
                      May 25 at 14:54




                      @OleTange See the edit.
                      – Sergiy Kolodyazhnyy
                      May 25 at 14:54










                      up vote
                      2
                      down vote













                      using Perl:



                      perl -ne 'mkdir for /^(w+)/' list.txt


                      Or



                      perl -ne 'mkdir for /^([^/]+)/' list.txt


                      if we want to accept spaces on dir-names






                      share|improve this answer


















                      • 1




                        perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
                        – dessert
                        May 24 at 21:03














                      up vote
                      2
                      down vote













                      using Perl:



                      perl -ne 'mkdir for /^(w+)/' list.txt


                      Or



                      perl -ne 'mkdir for /^([^/]+)/' list.txt


                      if we want to accept spaces on dir-names






                      share|improve this answer


















                      • 1




                        perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
                        – dessert
                        May 24 at 21:03












                      up vote
                      2
                      down vote










                      up vote
                      2
                      down vote









                      using Perl:



                      perl -ne 'mkdir for /^(w+)/' list.txt


                      Or



                      perl -ne 'mkdir for /^([^/]+)/' list.txt


                      if we want to accept spaces on dir-names






                      share|improve this answer














                      using Perl:



                      perl -ne 'mkdir for /^(w+)/' list.txt


                      Or



                      perl -ne 'mkdir for /^([^/]+)/' list.txt


                      if we want to accept spaces on dir-names







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 25 at 12:27









                      αғsнιη

                      22.9k2191150




                      22.9k2191150










                      answered May 24 at 19:06









                      JJoao

                      1,24059




                      1,24059







                      • 1




                        perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
                        – dessert
                        May 24 at 21:03












                      • 1




                        perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
                        – dessert
                        May 24 at 21:03







                      1




                      1




                      perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
                      – dessert
                      May 24 at 21:03




                      perl -ne 'mkdir for /^([^/]+)/' list.txt to cover spaces in dir names. I finally need to learn Perl – thank you!
                      – dessert
                      May 24 at 21:03










                      up vote
                      0
                      down vote













                      GNU Parallel may be overkill for the task, but if you are going to do other stuff for each line, then it may be useful:



                      cat myfile.txt | parallel --colsep / mkdir 1
                      parallel -a myfile.txt --colsep / mkdir 1


                      It deals correctly with input like:



                      A 12"x4" dir/B b/C c





                      share|improve this answer


























                        up vote
                        0
                        down vote













                        GNU Parallel may be overkill for the task, but if you are going to do other stuff for each line, then it may be useful:



                        cat myfile.txt | parallel --colsep / mkdir 1
                        parallel -a myfile.txt --colsep / mkdir 1


                        It deals correctly with input like:



                        A 12"x4" dir/B b/C c





                        share|improve this answer
























                          up vote
                          0
                          down vote










                          up vote
                          0
                          down vote









                          GNU Parallel may be overkill for the task, but if you are going to do other stuff for each line, then it may be useful:



                          cat myfile.txt | parallel --colsep / mkdir 1
                          parallel -a myfile.txt --colsep / mkdir 1


                          It deals correctly with input like:



                          A 12"x4" dir/B b/C c





                          share|improve this answer














                          GNU Parallel may be overkill for the task, but if you are going to do other stuff for each line, then it may be useful:



                          cat myfile.txt | parallel --colsep / mkdir 1
                          parallel -a myfile.txt --colsep / mkdir 1


                          It deals correctly with input like:



                          A 12"x4" dir/B b/C c






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited May 25 at 11:44

























                          answered May 25 at 11:26









                          Ole Tange

                          9711719




                          9711719






















                               

                              draft saved


                              draft discarded


























                               


                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1039649%2fcreate-directories-with-a-name-from-txt-file-which-contain-character%23new-answer', 'question_page');

                              );

                              Post as a guest













































































                              Popular posts from this blog

                              pylint3 and pip3 broken

                              Missing snmpget and snmpwalk

                              How to enroll fingerprints to Ubuntu 17.10 with VFS491