I would like to clear the content of many log files of a given directory recursively, without deleting every file. Is that possible with a simple command?
I know that I can do > logs/logfile.log one by one, but there are lots of logs in that folder, and that is not straightforward.
I am using macOS Sierra by the way.
Thanks to #chepner for showing me the better way to protect against double quotes in the file names:
You can use find to do it
find start_dir -type f -exec sh -c '> "$1"' _ {} \;
And you could add extra restrictions if you don't want all files, like if you want only files ending in .log you could do
find start_dir -type f -name '*.log' -exec sh -c '> "$1"' _ {} \;
As macOS includes Perl anyway:
perl -e 'for(<logs/*log>){truncate $_,0}'
Or, more succinctly, if you use homebrew and you have installed GNU Parallel (which is just a Perl script), you can do:
parallel '>' ::: logs/*log
Related
I'm trying to source a file that I can get from the output of find using these commands:
find ./ -iname activate.fish -exec source {} \;
and
find ./ -iname activate.fish -exec builtin source {} \;
But both these commands give the error of the form find: ‘source’: No such file or directory or find: ‘builtin’: No such file or directory. Seems like exec of find is not able to recognize fish's builtins ?
What I basically want to achieve is a single command that will search for Python's virtualenv activate scripts in the current directory and execute them.
So doing something like -exec fish -c 'source {}; \ would not help. I've tried it as well and it doesn't error out but does not make the changes either.
Any ideas what can be done for this ?
Thanks!
Perhaps you need:
for file in (find ./ -iname activate.fish)
source $file
end
# or
find ./ -iname activate.fish | while read file
source $file
end
Command substitution executes the command, splits on newlines, and returns that list.
As mentioned in comments, seems like -exec does not run in or affect the current shell environment. So find -exec is not gonna work for my use case.
Instead, this will work:
source (find ./ -iname activate.fish)
I would like to clear the content of many log files of a given directory recursively, without deleting every file. Is that possible with a simple command?
I know that I can do > logs/logfile.log one by one, but there are lots of logs in that folder, and that is not straightforward.
I am using macOS Sierra by the way.
Thanks to #chepner for showing me the better way to protect against double quotes in the file names:
You can use find to do it
find start_dir -type f -exec sh -c '> "$1"' _ {} \;
And you could add extra restrictions if you don't want all files, like if you want only files ending in .log you could do
find start_dir -type f -name '*.log' -exec sh -c '> "$1"' _ {} \;
As macOS includes Perl anyway:
perl -e 'for(<logs/*log>){truncate $_,0}'
Or, more succinctly, if you use homebrew and you have installed GNU Parallel (which is just a Perl script), you can do:
parallel '>' ::: logs/*log
The release tarball from the maintainer for this project contains vala generated c files.
I'm looking for a solution to look for the .vala files and remove the equivalent .c file
For example
directory\file1.vala
directory\file1.c
directory\file3.c
directory\subdirectory\file2.vala
directory\subdirectory\file2.c
directory\subdirectory\file4.c
From the above I want to delete file1.c and file2.c but not file3.c and file4.c
So reaching for the trusty find I can use
find . -name "*.vala" -exec ls {} \;
This will list all vala files.
Going slightly further I can change the output to .c via
find . -name "*.vala" | sed -e 's/.vala/.c/'
Now I need to go one step further and delete those .c files.
I suppose I could redirect the output into another file and then write a shell script to loop round each line and delete the file.
Any thoughts on a better way? Is there a better way to clean up vala generated files?
Append this to your sed command:
| xargs echo rm -v
If everything looks okay remove echo.
Cyrus' recommendation to use xargs is probably more appropriate, but if your find supports -exec ... + you can also use:
find . -name "*.vala" -exec bash -c 'echo ${#/vala/c}' sh {} +
find . -name "*.vala" -exec bash -c 'rm ${#/vala/c}' sh {} +
(You can use \; as well as +, but the extra shell invocations will make it pretty slow if you have a lot of files. ) Note that this is equivalent to your sed and suffers from the same problem as the sed solution in handling files with names like avala.vala.
I have to execute command in bash for all files in a folder with the extension ".prot'
The command is called "bezogener_Spannungsgradient" and it's called like that:
bezogener_Spannungsgradient filename.prot
Thanks!
find . -maxdepth 1 -name \*.prot -exec bezogener_Spannungsgradient {} \;
-maxdepth <depth> keeps find from recursing into subdirectories beyond the given depth.
-name <pattern> limits find to files matching the pattern. The escape is necessary to keep bash from expanding the find option into a list of matching files.
-exec <cmd> {} \; executes <cmd> on each found file (replacing {} with the filename). If the command is capable of processing a list of files, use + instead of \;.
I generally recommend becoming familiar with the lots of other options of find; it's one of the most underestimated tools out there. ;-)
You could do this:
for f in *.prot; do
bezogener_Spannungsgradient "$f"
done
I'm trying to create a batch file in linux that will allow me to change extensions of files in multiple subdirectories. After much searching and experimenting i've found what seems to be a solution:
find /volume1/uploads -name "*.mkv" -exec rename .mkv .avi {} +
When running the script i get the following error:
find: -exec CMD must end by ';'
I've tried adding ; and \; (with or without +) but to no avail. What's wrong with the command and how can I fix it?
Edit: Running on a Synology NAS with DSM 4.2
you have to escape all characters that would be interpreted by bash. in your case these are the semicolon and the curly braces (you forgot to escape the latter in your code):
find /volume1/uploads -name "*.mkv" -exec rename .mkv .avi \{\} \;
the {} (in our case \{\}) is expanded to the filename, so the actual call would look like rename .mkv .avi /volume1/uploads/foo/bla.mkv (which is not the exact syntax the /usr/bin/rename needs, at least on my system).
instead it would be something like:
find /volume1/uploads -name "*.mkv" -exec rename 's/\.mkv$/.avi/' \{\} \;
UPDATE
if you don't want to (or cannot) use perl's rename script, you could use the following simple bash script and save it as /tmp/rename.sh
#!/bin/sh
INFILE=$1
OUTFILE="${INFILE%.mkv}.avi"
echo "moving ${INFILE} to ${OUTFILE}"
mv "${INFILE}" "${OUTFILE}"
make it executable (chmod u+x /tmp/rename.sh) and call:
find /volume1/uploads -name "*.mkv" -exec /tmp/rename.sh \{\} \;
UPDATE2
it turned out that this question is really not about bash but about busybox.
with a limited shell interpreter like busybox, the simplest solution is just to append the new file extension:
find /volume1/uploads -name "*.mkv" -exec mv \{\} \{\}.avi \;
Not sure how different find and rename commands are on your DSM 4.2 OS so try something like:
find /volume1/uploads -name "*.mkv" | while read filename;
do mv -v "${filename}" "$(echo "${filename}" | sed -e 's/\.mkv$/\.avi/')"
done