3

Say I have a directory structure that is like Parent_dir/<name>/<date>/

How can I use a bash script placed into Parent_dir to navigate through every /<name>/<date>/ subdirectory and create a blank text file named <name>_<date>.txt within /<name>/<date>/ subdirectory?

5
  • 1
    Are name and date placeholders as well?
    – Hölderlin
    Commented Apr 9, 2017 at 2:57
  • yes there's 20 different "name" directories (some have spaces if that matters) and 93 different "date" directories within each
    – Austin
    Commented Apr 9, 2017 at 2:58
  • edited my post to make it a bit more clear.
    – Austin
    Commented Apr 9, 2017 at 3:08
  • 1
    Where the new files would be created?
    – heemayl
    Commented Apr 9, 2017 at 3:18
  • sorry made another edit
    – Austin
    Commented Apr 9, 2017 at 3:19

3 Answers 3

4

From the Parent_dir:

for d in */*/; do f=${d/\//_}; touch -- "$d"/"${f::-1}.txt"; done

Note that touch will change the timestamp of any existing file.

You can do a dry-run first with replacing touch with echo:

for d in */*/; do f=${d/\//_}; echo -- "$d"/"${f::-1}.txt"; done
  • for d in */*/ lets us iterating over the directories two levels deep

  • f=${d/\//_} replaces first directory separator / with _ and save the output as variable f

  • "$d"/"${f::-1}.txt" expands to the directory name, followed by the desired filename; ${f::-1} strips off the last / from variable f

Note that, as the directory separator / is present with variable d, the / in "$d"/"${f::-1}.txt" is redundant; as almost all systems take // as single /, this should not be a problem. Alternately, you can drip /:

for d in */*/; do f=${d/\//_}; touch -- "${d}${f::-1}.txt"; done
1
  • Thanks! I'll try this out later because it looks very clean although the first post seemed to work for my needs :)
    – Austin
    Commented Apr 9, 2017 at 4:29
2

If you want the filenames to literally be named name_date.txt, try this:

#!/bin/bash
for dir in $(find . -maxdepth 2 -mindepth 2 -type d)
do
    touch "$dir"/name_date.txt
done

If you want the filenames to be <name>_<date>.txt, do this instead:

#!/bin/bash
IFS=$'\n'
for dir in $(find . -maxdepth 1 ! -path . -type d)
do
    for subdir in $(find "$dir" -mindepth 1 -type d)
    do
        base_dir=$(basename $dir)
        base_subdir=$(basename $subdir)

        touch "$base_dir"/"$base_subdir"/"$base_dir"_"$base_subdir".txt
    done
done
4
  • Thanks this works great except for it doesn't work for <name> directories that have spaces in them. Is there any quick fix for that?
    – Austin
    Commented Apr 9, 2017 at 3:30
  • Try now - the IFS should fix it. It's a bit of a hack, but should work.
    – Tal
    Commented Apr 9, 2017 at 3:33
  • Perfect much appreciated!
    – Austin
    Commented Apr 9, 2017 at 3:34
  • See Why is looping over find's output bad practice? Learn how to do it the right way and there won't be any need for "hacks"... Commented Apr 9, 2017 at 9:25
1
find . -type d -exec sh -c '
   case ${1//[!\/]/} in
      "//" ) f=${1:2}; f=${f/\//_}; :> "$1/$f.txt" ;;
      * ) false ;;
   esac
' {} {} \; -prune

for d in */*/; do
   f=${d/\//_}
   :> "${d%?}/${f%?}.txt"
done
1
  • Rakesh buddy, please add some explanation to your posts as they keep showing up in the Low Quality Post review queue due to the fact there's only code and no text (I just had to review three of them)... Commented Apr 9, 2017 at 9:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .