0

I have a text file with list of .XML files.

I need an absolute path of each XML in file.

Tried following shell script but after lots of try,find command is not working inside do tag.

    #!/bin/sh
    NAMES=`cat list2.txt`
    for NAME in $NAMES; 
   do
     echo "$NAME"
     find $PWD -type f -name "$NAME"
   done
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
sayali
  • 1

6 Answers6

2

A loop is the wrong way to address the problem. Crawling the directory tree for each file would be inefficient. You want to crawl the directory only once to file all the files. Like with:

find "$PWD" -type f -print0 | awk -F / '
   !list_processed {names[$0]; next}
   $NF in names' list.txt RS='\0' list_processed=1 -

That's assuming list.txt contains a list of file name (not path), one per line.

  • @CharlesAddis no, it's not. and a loop will take many times longer and cause a much larger CPU and disk I/O load on the system - even ignoring the inefficiency of shell code and shell loops, a loop would run find once for each line in list.txt rather than just once with a pipe. BTW, here's another variation on the same method using grep (and process substitution with sed) rather than awk: find "$PWD" -type f | grep -f <( sed -e 's/\./\\./g; s/^/\//; s/$/$/' list.txt). This one doesn't bother with -print0 because it's unlikely that list.txt has NUL terminated lines. – cas Jul 29 '17 at 00:47
1

Your code has a bug, your iteration is wrong.

I would use this way in iteration:

#!/bin/sh
while IFS= read -r NAME; do
  echo "$NAME"
  find "$PWD" -type f -name "$NAME"
done <list.txt
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • Not working,its just echo the file names but find fails to give absolute path. – sayali Jul 28 '17 at 09:10
  • His code does not have a bug and his iteration is correct. – Charles D Pantoga Jul 29 '17 at 00:39
  • @sayali Change "$PWD" to /. Does it work now? – Chris Davies Jul 29 '17 at 04:18
  • @sayali how does it fail? Error message (what message) or wrong output (what output do you get and what do you expect instead)? We cannot see what you can see so instead of just saying that it doesn't work you have to tell us how and why it doesn't work. Maybe tell us one of the filenames in your text file and confirm to us where in the filesystem that file is found. As an example. – Chris Davies Jul 29 '17 at 04:19
0

The PWD variable is not defined
Add before the cycle begins
PWD=<path>

Serg B
  • 1
0

Here is an alternate way you can solve the problem. Maybe this way will work for you. This only calls find once, making it much faster and more efficient.

stackoverflow.sh

#!/bin/sh

declare -a NAME_LIST=(`cat list2`)
#declare -i LIST_SIZE=${#NAME_LIST[*]}
declare EXPRESSION="find ${PWD} "

# build up the find command
for name in ${NAME_LIST[@]}; do
    if test ${NAME_LIST[0]} = ${name}; then
        EXPRESSION+="-type f -and -name $name "
    else
        EXPRESSION+="-or -type f -and -name $name "
    fi
done

eval $EXPRESSION

In my enhanced version, $EXPRESSION is equal to:

find /Users/charlie -type f -and -name one -or -type f -and -name two -or -type f -and -name three -or -type f -and -name four -or -type f -and -name five -or -type f -and -name six -or -type f -and -name seven -or -type f -and -name eight

Of course, your original code works fine for me in bash on OSX (which has the same find command as you do on linux). Obviously, since you're also echoing the name of just the file (and not the path) the output will be a list of both the files and the paths.

The only thing that I think could be causing issues is if your file is unicode encoded and the actual filenames themselves do not have unicode. Otherwise it DOES print the absolute path to the file.

stackoverflow.sh:

#!/bin/sh

NAMES=`cat list2`

for name in $NAMES; do
  echo $name >&2
  find $PWD -type f -name $name
done

Executing the program:

$ charlie on macbook in ~
❯❯ cat list2
one
two
three
four
five
six
seven
eight

$ charlie on macbook in ~
❯❯ ./stackoverflow.sh
one
/Users/charlie/one
two
/Users/charlie/src/web/two
three
/Users/charlie/misc/three
four
/Users/charlie/four
five
/Users/charlie/Documents/five
six
/Users/charlie/Documents/Ideas/six
seven
/Users/charlie/seven
eight
/Users/charlie/Documents/eight

$ charlie on macbook in ~
❯❯ ./stackoverflow.sh
/Users/charlie/one
/Users/charlie/src/web/two
/Users/charlie/misc/three
/Users/charlie/four
/Users/charlie/Documents/five
/Users/charlie/Documents/Ideas/six
/Users/charlie/seven
/Users/charlie/Documents/eight

$ charlie on macbook in ~
❯❯ ./stackoverflow.sh 2>stderr-output
/Users/charlie/one
/Users/charlie/src/web/two
/Users/charlie/misc/three
/Users/charlie/four
/Users/charlie/Documents/five
/Users/charlie/Documents/Ideas/six
/Users/charlie/seven
/Users/charlie/Documents/eight

$ charlie on macbook in ~
❯❯ cmp list2 stderr-output

$ charlie on macbook in ~
❯❯ echo $?
0
  • Issues may be caused by special characters, like spaces in filenames. Try renaming Documents to Docu ments in list2 – xhienne Jul 29 '17 at 01:02
  • Why would I put spaces in a directory or filename? I use unix. You just don't do stuff like that if you're a unix/linux user. This isn't windows. – Charles D Pantoga Jul 29 '17 at 01:04
  • But, if I knew a filesystem had those issues it would be trivial to work around them using variable expansion/substitution... IE: ${name// /\\ }... and I doubt his filenames have spaces in them, considering he's using spaces as a word separator to build up his list of filenames... – Charles D Pantoga Jul 29 '17 at 01:05
  • root# echo $name => "Hello World" | root# echo ${name// /\ } => "Hello\ World" | root# echo ${name/' '/'\ '} => "Hello\ World" ..... @xhienne – Charles D Pantoga Jul 29 '17 at 01:09
  • 2
    First, you wouldn't do this but you are not the OP. Second, Cygwin users are welcome to ask questions here. Finally, by special characters, I mean all sort of special characters that may be interpreted by bash: *, ?, etc. You don't have to resort to a never-ending list of substitutions like ${name// /\\ }, ${name//*/\\*}, etc. Just quote your variables, that's all. – xhienne Jul 29 '17 at 01:17
  • @xhienne you say that, but windows does not allow filenames to contain either of those characters. Windows restricts users from creating files that contain any of the following characters: <>:"/\|?*, which blows your theory that a cygwin user reading a file from the windows host operating system would contain those special characters. – Charles D Pantoga Jul 29 '17 at 01:37
0
for NAME in $(cat list2.txt); do readlink -e $NAME; done
Ab08
  • 1
  • Welcome to Unix.SE. It would be useful if you could explain what your answer does, and how it solves whatever problem is exhibited in the question. – Stephen Kitt Aug 01 '17 at 13:38
0

Thank You for all your responses.
Issue has been solved. :)
There might be some issue to text file I am passing,I just created new text file and copying all data to it.

Passing this new file in for loop works fine with my code itself like:

#!/bin/sh
NAMES=`cat myNewList.txt`
for NAME in $NAMES; 
 do
  find $PWD -type f -name "$NAME"
 done
Sayali
  • 1