What is the python equivalent to the "*" list all command? - python-3.x

What character do I use similar to "*" in other languages to list/see all of the files, where it doesn't matter what the beginning part is but they all end if say .traj.
So like I want to list the following files from a directory with the following file names
test1. exe
test1.traj
test2.exe
test2.traj
test3.exe
test3.traj
where I want to only list:
test1.traj
test2.traj
test3.traj
in other languages I might do:
print, *.traj

Assuming this is Python3 as that's what you have tagged.
Use the glob module
Like so:
files = glob.glob('*.traj')
for f in files:
print(f)

Related

how to search everywhere within a specific directory (including sub folders) using python

basically, as the title says, I want to be able to use a python script where I give a path/directory, and a file name, and it will search all the way through the path/directory just to find the file name.
I have tried using glob.glob() however it will only search within the directory and not within subfolders and such from what I have found.
From the glob.glob() docs (emphasis mine), starting at Python 3.5:
If recursive is true, the pattern "**" will match any files and zero or more directories, subdirectories and symbolic links to directories.
So you just put ** into your pattern where you want it to expand to any subdirectories and files therein and add recursive=True as a keyword argument.
For example, given a directory structure like
a
+-b
| +-d
| +-f
+-c
+-e
with your current working directory being a, you can do:
>>> from glob import glob
>>> glob("**", recursive=True)
['c', 'c/e', 'b', 'b/d', 'b/d/f']
For your specific use case of searching for a filename in all subdirectories, you'd do:
>>> glob("**/f", recursive=True)
['b/d/f']
Note that ** patterns also work in pathlib.Path.glob() and pathlib paths are often more comfortable to use than the more low-level os.path and glob modules.

Find command with quotation marks results in "no such file"

In my directory there are the files:
file1.txt fix.log fixRRRRRR.log fixXXXX.log output.txt
In order to understand the find command, I tried a lot of stuff among other things I wanted to use 2 wildcards. Target was to find files that start with an f and have an extension starting with an l.
$ find . f*.l*
./file1.txt
./fix.log
./fixRRRRRR.log
./output.txt
./fixXXXX.log
fix.log
fixRRRRRR.log
fixXXXX.log
I read in a forum answer to use quotation marks with find find . "f*.l*" with the result: `
./file1.txt
./fix.log
./fixRRRRRR.log
./output.txt
./fixXXXX.log
It results in find: ‘f*.l*’: No such file or directory
What am I doing wrong, where is my error in reasoning?
Thanks for an answer.
find doesn't work like that. In general find's call form looks like:
find [entry1] [entry2] ... [expressions ...]
Where an entry is a starting point where find starts the search for files.
In your case, you haven't actually supplied any expressions.
In the first command (without quotes), the shell expands the wildcards to a list of matching files (in the current directory), then passes the list to find as arguments. So find . f*.l* is essentially equivalent to find . fix.log fixRRRRRR.log fixXXXX.log. As a result, find treats all of those arguments as directories/files to search (not patterns to search for), and lists all files under ., (everything) then all files under fix.log (it's not a directory, so that's just the file itself), then all files under fixRRRRRR.log and finally all files under fixXXXX.log.
In the second one (with quotes) it searches for all files beneath the current directory (.) and tries the same for the file literally called "f*.l*".
Actually you are likely seeking for the "-name" expression, which may be used like this:
find . -name "f*.l*"

How can I add per-file defines to a scons project

I'm in the process of porting a makefile project to scons and I can't figure out how to create a unique #define for each file. I would like to have the base filename for each file defined in order to support some custom debug macros. In the makefile, I'm able to do this with the following definition.
-DBASE_FILE_NAME=\"$(<F)\"
I'm not sure how to do this or if it is even possible in scons and would appreciate any feedback.
After some experimentation, the following seems to work.
import os
from glob import glob
# use Python glob, not scons Glob!
CPP_FILES = glob('./src/*.cpp')
env = Environment(CPPPATH='./include', etc...)
for f in CPP_FILES:
env.Object(f, CPPDEFINES={'BASE_FILENAME' : "\\\"" + os.path.basename(f) + "\\\""})
O_FILES = [os.path.splitext(f)[0] + '.o' for f in CPP_FILES]
env.Program('myprogram', O_FILES)
This lets me define things on a per-file basis without listing the files out individually.
Perhaps the following? (Haven't tried it, but something along those lines should work)
env.Program('filename.c',CPPDEFINES='-DBASE_FILE_NAME=\"$SOURCE\"')

Is there a way to undo a batch-rename of file extensions?

Ok so I kinda dropped the ball. I was trying to understand how things work. I had a few html files on my computer that I was trying to rename as txt files. This was strictly a learning exercise. Following the instructions I found here using this code:
for file in *.html
do
mv "$file" "${file%.html}.txt"
done
produced this error:
mv: rename *.html to *.txt: No such file or directory
Long story short I ended up going rogue and renaming the html files, as well as a lot of other non html files as txt files. So now I have files labeled like
my_movie.mp4.txt
my_song.mp3.txt
my_file.txt.txt
This may be a really dumb question but.. Is there a way to check if a file has two extensions and if yes remove the last one? Or any other way to undo this mess?
EDIT
Doing this find . -name "*.*.txt" -exec echo {} \; | cat -b seems to tell me what was changed and where it is located. The cat -b part is not necessary but I like it. This still doesn't fix what I broke though.
I'm not sure if terminal can check for extensions "twice", but you can check for . in every name an if there's more than one occurence of ., then your file has more extensions. Then you can cut the extension off with finding first occurence of . in a string when going backwards... or last one if checking characters in string in a normal way.
I have a faster option for you if you can use python. You can strip the extension with:
for file in list_of_files:
os.rename(file,os.path.splitext(file)[0])
which can give you from your file.txt.txt your file.txt
Example:
You wrote that your command tells you what has changed, so just take those changed files and dump them into a file(path to file per line). Then you can easily run this:
with open('<path to list>') as f:
list_of_files = f.readlines()
for file in list_of_files:
os.rename(file.strip('\n'), os.path.splitext(file.strip('\n'))[0])
If not, then you'd need to get the list from python:
import os
results = []
for root, folder, filenames in os.walk(<your path to folder>):
for filename in filenames:
if filename.endswith('.txt.txt'):
results.append(os.path.join(root, filename))
With this you got a list of files ending with .txt.txt like this <your folder>\\<path_to_file>.
Get a path to your directory used in os.walk() without folder's name(it's already in list) so it'll be like this:
e.g. os.walk('/home/me/directory') -> path='/home/me/' and res is item already in a list, which looks like directory/...
for res in results:
path = '' # set the path here
file = os.path.join(path,r)
os.rename(file, os.path.splitext(file)[0])
Depending on what files you want to find change .txt.txt in if filename.endswith('...') to whatever you like and os.rename() will take file's name without extension which in your case means it strips the additional extension you don't want to have.

Shell script to use a list of filenames in a CSV to copy files from one directory to another

I have a list of files that I need to copy. I want to recursively search a drive and copy those files to a set location if that filename exists in the list. The list is a text file/
the text file would look something like this:
A/ART-FHKFX1.jpg
B/BIG-085M.jpg
B/BIG-085XL.jpg
L/LL-CJFK.jpg
N/NRT-56808EA.jpg
P/PFE-25.10.jpg
P/PFE-7/60.jpg
P/PFE-7L.20.jpg
P/PFE-8.25.jpg
P/PFE-9.15.jpg
P/PFE-D11.1.tiff
P/PFE-D11.1.tiff
P/PFE-D12.2.tiff
P/PFE-D12.2.tiff
using find will take a lot of time, try to use locate if possible.
what will happen when there's several matches? like searching for foo.bar and having a/foo.bar and also b/foo.bar what would you do in that case?
your csv seems to include a path, given the previous I'll assume those paths are actually valid from where the script is run so in that case just do this:
#!/bin/bash
while read path; do
cp "$path" "$1"
done
then call it like this:
teh_script /path/to/destination < csv-file.csv

Resources