olealgo
olealgo

Reputation: 479

bash / linux - touch/mkdir from string in file

I have a file full of filenames and directory names. Example:

DIR,/mnt/sdcard/mydir1/
DIR,/mnt/sdcard/mydir2/
DIR,/mnt/sdcard/mydir3/
FILE,/mnt/sdcard/mydir1/file1.txt
FILE,/mnt/sdcard/mydir2/file1.txt
FILE,/mnt/sdcard/mydir3/file1.txt

with total around 30.000 entries of directories and filenames. I need to create all the directories, sub-directories and files (empty ones) inside a specified folder. And I also want to skip all the directories/files that already exist!

Currently I have this, but I am hoping there is a better way, as this is very slow and consumes a lot of CPU:

#!/bin/bash
cd /home/mydir/dummydir/

for file in *.tree.txt; do

MEMBER=$(echo $file | cut -d '.' -f1)
DIRECTORY=/home/mydir/dummydir/$MEMBER

while read line
do

if [[ $line == FILE,* ]]
then

CUTOFFILE=$(echo "$line" | cut -c 6-)
touch "$DIRECTORY$CUTOFFILE"

else

CUTOFFDIR=$(echo "$line" | cut -c 5-)
if [[ ! -d "$DIRECTORY$line" && $line == DIR,* ]]; then
mkdir -p "$DIRECTORY$CUTOFFDIR"
fi


fi

done < $file
done

Upvotes: 0

Views: 2669

Answers (1)

John Kugelman
John Kugelman

Reputation: 361595

#!/bin/bash
cd /home/mydir/dummydir/

for file in *.tree.txt; do
    dir=${file%.tree.txt}

    while IFS=, read type path; do
        case $type in
            FILE) touch "$dir/$path";;
            DIR)  mkdir -p "$dir/$path";;
            *)    echo "bad line: $type,$path" >&2;;
        esac
    done < "$file"
done

I'm not a huge fan of cut, so I replaced it with other parsing methods.

  • With each line containing two fields separated by a comma, you can cut out a lot of code by having read parse the line and store the two parts in separate variables. You can do that by temporarily overriding the $IFS variable with IFS=, which tells read to use , as the field separator. Then read type path reads the two parts into $type and $path.

  • Both touch and mkdir -p are harmless when applied to files or directories that already exist, so you could probably omit the checks for existing files and just always do them.

  • Since you start the script by cding to /home/mydir/dummydir, you don't really need to repeat that later.

  • ${file%.tree.txt} is a shorter way of stripping off .tree.txt. Another way is $(basename "$file" .tree.txt).

Upvotes: 3

Related Questions