1

I wanted to save the names of all files in each sub directory into a text file in that sub directory, so I wrote this script:

#!/bin/bash
for X in "$PWD" *
do  
    if [ -d "$X" ];
    then
        cd "$X"
        files="$(ls)"
        echo "$files" >> filesNames.txt
    fi
done

but, I cannot enter sub directories using:

cd "$X"

What is wrong here?

  • What error message do you see? – JigglyNaga May 19 '16 at 11:24
  • Why do you quote all the uses of variables but not do cd "$X"? If there is a space in the directory name then cd will not work – Anthon May 19 '16 at 11:27
  • @JigglyNaga Nothing, it produces filesnames.txt file containing the name of sub directories in the parent directory. – Ali May 19 '16 at 11:27
  • @Anthon, I checked it. No difference, still generates the same unexpected result. – Ali May 19 '16 at 11:29
  • 2
    You've forgotten to cd .. back out of each subdirectory after processing it. So the if [ -d "$X" ] test fails, hence you seeing no error messages. – JigglyNaga May 19 '16 at 11:46
1

Per your comments, you only have to descend one level deep. In that case you could use a glob to iterate over directories names and for each dir save file paths in an array, then print the last element of each path to fileNames.txt:

#!/bin/sh

for dir in "$PWD"/*/; do
arr=( "$dir"* )
printf %s\\n "${arr[@]##*/}" > "$dir"filesNames.txt
done

To exclude symlinks just add a condition e.g. if [[ ! -L "${dir%?}" ]]; then arr...

  • That's it! Thank you very much and thank you all! – Ali May 19 '16 at 12:44
  • Replace "${arr[@]##*/}" with "${arr[@]}" if you need the full paths to your files. Also, add shopt -s dotglob at the top if you need to select hidden (dot) files too. – don_crissti May 23 '16 at 19:23
1

You need to cd out of each subdirectory before trying the next one. Inserting...

cd ..

at the end of the loop would fix this for the subdirectories, but breaks when you do it in the top directory first. A cd .. from there will take you up another level, so the other directories aren't visible any more.

You can address all of this by saving the top directory in a variable, and cd to there each time:

#!/bin/bash

TOPDIR="$PWD"
for X in "$PWD" * ; 
do
        if [ -d "$X" ] ;
        then
                cd "$X"
                files="$(ls)"
                echo "$files" >> filesNames.txt
                cd "$TOPDIR"
        fi
done

You might also want to change >> to >, if you don't want to keep all the results from previous runs.

0
#!/bin/bash
for X in $PWD/* ; do
        if [ -d "$X" ] ; then # first depth directories
                cd "$X" ;
                files="$(ls)" ;
                printf "$files\n" >> filesNames.txt ;
        else # regular files:
                printf "$X\n" >> fileNames.txt ;
        fi ;
done ;

It may be that what you are trying to achieve can generalised using find - using additional options (man find) for each $X - such as:

files=$(find ${PWD} -type f) ;
printf "$files\n" >> filesNames.txt ;
  • This prints all names into a single file at the top. The OP requires a text file in each subdirectory. – JigglyNaga May 19 '16 at 11:53
  • So in the first example prefix the piped output with the current "$X" path eg: printf "$files\n" >> $X/filesNames.txt ; – aphorise May 19 '16 at 11:56
  • @aphorise Thanks, it is a nice suggestion, but: 1. the result still will be saved in the parent directory 2. It contains the name of all subdirs, too. – Ali May 19 '16 at 12:11
0

Try this instead:

find . -type d -exec sh -c "cd {} ; ls | grep -v '^filesNames.txt$' > filesNames.txt" \;

This finds all directories beneath the current directory and, for each one, it cds into the directory and writes the directory listing to a filesNames.txt (excluding that file from the list).

If you want the filesNames.txt files to be in the lists too, remove the | grep -v ... from the command:

find . -type d -exec sh -c "cd {} ; ls > filesNames.txt" \;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.