Clear multiple files - bash

How can I clear/empty multiple files using bash?
For a single file you can use
> foo.log
But I've tried
> *.log;
find . -maxdepth 1 -name "*.log" | xargs >;
But they don't seem to work. How can I do this?

The redirection must be performed in a shell, one at a time.
... -exec sh -c "> {}" \; ...
...
for f in *.log
do
> "$f"
done

try this , it works :
find . -maxdepth 1 -name "*.log" | xargs -t -n1 -I '{}' perl -e "open(I,'>{}')"

Related

How to stop bash loop from looping over files created during the loop?

I want to run a loop over all files of a particular extension in a directory:
for i in *.bam
do
...
done
However, if the command that I run inside the loop creates a temporary file of the same extension, the loop tries to process this new tmp file as well. This is unwanted. So, I thought the following would solve the problem: first list all the *.bam files in the directory, save that list to a variable, and then loop over this saved list:
list_bam=$(for i in *.bam; do echo $i; done)
for i in $list_bam
do
...
done
To my surprise, this runs into the same problem! Could someone please explain the logic behind this and how to fix it so that the loop only processes the pre-existing .bam files?
Instead of a loop you can use find and xargs
find . -maxdepth 1 -type f -name "*.bam" -print0 | \
xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"'
or
find . -maxdepth 1 -type f -name "*.bam" -print0 | \
xargs -0 -I{} bash -c 'echo "$1" > "$1.new.bam"' -- {}
example:
$ touch a.bam b.bam
$ ls
a.bam b.bam
$ find . -maxdepth 1 -type f -name "*.bam" -print0 | \
xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"'
$ ls
a.bam a.bam.new.bam b.bam b.bam.new.bam
You should perhaps make sure that your globbing expression *.bam couldn't be interpreted afterward with something like:
list_bam=$(ls *.bam)
...
...but, as noticed by #glenn in the comments, this is a bad idea.
Something similar should be made using a find ... -print0 | xargs -0 ... command template.

Running multiple commands with xargs - for loop

Based on the top answer in Running multiple commands with xargs I'm trying to use find / xargs to work upon more files. Why the first file 1.txt is missing in for loop?
$ ls
1.txt 2.txt 3.txt
$ find . -name "*.txt" -print0 | xargs -0
./1.txt ./2.txt ./3.txt
$ find . -name "*.txt" -print0 | xargs -0 sh -c 'for arg do echo "$arg"; done'
./2.txt
./3.txt
Why do you insist on using xargs? You can do the following as well.
while read -r file; do
echo $file
done <<<$(find . -name "*.txt")
Because this is executed in the same shell, changing variables is possible in the loop. Otherwise you'll get a sub-shell in which that doesn't work.
When you use your for-loop in a script example.sh, the call example.sh var1 var2 var3 will put var1 in the first argument, not example.sh.
When you want to process one file for each command, use the xargs option -L:
find . -name "*.txt" -print0 | xargs -0 -L1 sh -c 'echo "$0"'
# or for a simple case
find . -name "*.txt" -print0 | xargs -0 -L1 echo
I ran across this while having the same issue. You need the extra _ at the end as place holder 0 for xargs
$ find . -name "*.txt" -print0 | xargs -0 sh -c 'for arg do echo "$arg"; done' _

Copying the result of a find operation in shell

I want to find a file, and simultaneously copy it to another directory like this:
cp (find . -name myFile | tail -n 1) dir/to/copy/to
But this says unexpected token `find'
Is there a better way to do this?
You may use a pipeline:
find . -name 'myFile' -print0 | tail -z -n 1 | xargs -0 -I {} cp {} /dir/to/copy/to/
Using -print0 option to address filenames with whitespace, glob characters
find . -name 'myFile' -print0 | tail -n 1 | xargs -0 -I {} cp {} /dir/to/copy/to/
Two options are available-
Appended the missing $() - to evaluate command (not sure the purpose of tail command, only required for samefile in multiple directories)
cp $(find . -name myFile | tail -n 1) dir/to/copy/to
find . -name myFile -type f -exec cp {} dir/to/copy/to \;

What is the correct Linux command of find, grep and sort?

I am writing a command using find, grep and sort to display a sorted list of all files that contain 'some-text'.
I was unable to figure out the command.
Here is my attempt:
$find . -type f |grep -l "some-text" | sort
but it didn't work.
You need to use something like XARGS so that the content of each file passed through the pipe | is made available for grep.
XARGS: converts input from standard input into arguments to a command
In my case, I have files1,2,3 and they contain the word test. This will do it.
za:tmp za$ find . -type f | xargs grep -l "test" | sort
./file1.txt
./file2.txt
./file3.txt
or
za:tmp za$ find . -type f | xargs grep -i "test" | sort
./file1.txt:some test string
./file2.txt:some test string
./file3.txt:some test string
You can use it in any unix:
find . -type f -exec sh -c 'grep "some text" {} /dev/null > /dev/null 2>&1' \; -a -print 2> /dev/null|sort
A more optimized solution that works only with GNU-grep:
find . -type f -exec grep -Hq "some-text" {} \; -a -print 2> /dev/null|sort

Need a shell script that deletes all files except *.pdf

Can anyone write a shell script that deletes all the files in the folder except those with pdf extension?
This will include all subdirectories:
find . -type f ! -iname '*.pdf' -delete
This will act only in the current directory:
find . -maxdepth 1 -type f ! -iname '*.pdf' -delete
$ ls -1 | grep -v '.pdf$' | xargs -I {} rm -i {}
Or, if you are confident:
$ ls -1 | grep -v '.pdf$' | xargs -I {} rm {}
Or, the bulletproof version:
$ find . -maxdepth 1 -type f ! -iname '*.pdf' -delete
This should do the trick:
shopt -s extglob
rm !(*.pdf)
ls | grep -v '.pdf$' | xargs rm
This will filter all files that don't end in PDF, and execute RM on them

Resources