Can someone tell me why my variable will only return all .txt files or all .log files but not both together. I thought I understood this, as I have used similar cases before with an if statement and qn endswith method of text or log extension. But, with getting files from a server it's only allowing me to get one or another. I'm sure it's the syntax ... I have very little experience with Python. Any help is appreciated:
This line works fine or a variation with .txt:
apattern = '"*.log"'
However, this line searches for .log files only:
apattern = (('"*.txt" ') or ('"*.log" '))
Code:
import paramiko
import sys
import os
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.5.48.72', username='root', password='*****')
apath = '/'
apattern = '"*.{txt,log}"' #(('"*.txt" ') and ('"*.log" '))
rawcommand = 'find {path} -name {pattern}'
command = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = ssh.exec_command(command)
filelist = stdout.read().splitlines()
ftp = ssh.open_sftp()
for afile in filelist:
(head, filename) = os.path.split(afile)
print(filename)
ftp.get(开发者_Python百科afile, 'c:\\ANewOne\\' + filename) #'./'+filename)
ftp.close()
ssh.close()
However, this line searches for .log files only:
No it doesn't, it searches for .txt files only. :-) The reason is that (('"*.txt" ') or ('"*.log" '))
evaluates to '"*.txt"
.
There's a (somewhat involved) reason for this as well: the or
operator takes the logical or
of two Boolean (true/false) objects. Since they aren't Boolean objects but strings, they are checked for "truthiness." In the case of a string, if they have any characters in them, they are considered to be True
. Both your strings are "truthy."
Due to short-circuiting, the second operand of or
isn't evaluated if the first operand is truthy (since True or
anything is always true, there's no point). And finally, or
always returns the last argument it evaluated, so in this case you get the first string: '"*.txt"'
.
Your misconception here is that you think Python is going to wait to evaluate the or
until you do whatever it is you're using to search the filenames. It doesn't. The expression you have given is fully evaluated when it is assigned to apattern
and it evaluates to the single string '"*.txt"'
.
There are a few ways to do what you want:
- If your search method allows it, you can use a single pattern that will match both extensions, such as marc's
'"*.{txt,log}"'
for UNIX shells. - You can have Python get the names of all the files and check each yourself to see if it matches either pattern, processing it if so. This is the approach g.d.d.c is suggesting.
- You can do two searches and combine the results. If there might be duplicates (there wouldn't be in this case) and you don't care about what order the filenames are in, you can use a
set
to remove the dupes:filenames = set(list1 + list2)
.
apattern = '"*.{txt,log}"'
Should combine the extensions using unix-style shell expansion.
Another variant for the find
utility would be
apattern = '"*.txt" -o -name "*.log"'
Maybe you can try this, too. This will construct the command
find {path} -name "*.txt" -o -name "*.log"
In Python, when doing assignments, using or doesn't make a ton of sense because your first condition is "True-ish" (it's not a blank string), so the second half of that assignment doesn't get evaluated. If you have a file name somewhere, you can do something like this:
if filename.endswith('txt') or filename.endswith('log')
Better, though, would be to use something like this:
ext = os.path.splitext(filename)[-1]
if ext in ('txt', 'log'):
# some other processing here.
the first part of the or evaluates to True so it will not do the second part (*.txt).
精彩评论