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?

Austin
  • 221
  • 1
  • 2
  • 11

3 Answers3

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
heemayl
  • 54,820
  • 8
  • 124
  • 141
  • Thanks! I'll try this out later because it looks very clean although the first post seemed to work for my needs :) – Austin Apr 09 '17 at 04: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
Tal
  • 1,982
  • 5
  • 22
  • 36
  • Thanks this works great except for it doesn't work for directories that have spaces in them. Is there any quick fix for that? – Austin Apr 09 '17 at 03:30
  • Try now - the IFS should fix it. It's a bit of a hack, but should work. – Tal Apr 09 '17 at 03:33
  • Perfect much appreciated! – Austin Apr 09 '17 at 03:34
  • See [Why is looping over find's output bad practice?](http://unix.stackexchange.com/q/321697) Learn how to do it the right way and there won't be any need for "hacks"... – don_crissti Apr 09 '17 at 09: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
  • 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)... – don_crissti Apr 09 '17 at 09:21