Make with dependencies from a file - makefile

I want to write a Makefile that reads a file list.txt and produces result.tar containing the contents. If there is a change in either the list.txt file, or any of the files it points at, then result.tar should be rebuilt. How can I express this in a Makefile? The closest I have come is:
result.tar : list.txt
cat list.txt | xargs tar -cf result.tar
But this omits the dependency on the contents of list.txt.

I think there should be something like this:
result.tar : list.txt $(shell cat list.txt)
cat list.txt | xargs tar -cf result.tar
Or, a bit better (extracting list.txt to a variable and using automatic variables):
LIST_FILE := list.txt
result.tar : $(LIST_FILE) $(shell cat $(LIST_FILE))
cat $< | xargs tar -cf $#

Related

Listing existing files that are not present in a list using shell

How do I list files that exist, but not present in the list? More specifically, I'd like to remove *.cpp files not listed in Build. Something like this lists files that are present in both the current directory and the Build file:
ls *.cpp | xargs -I % bash -c 'grep % Build'
However, the following line is incorrect of course:
ls *.cpp | xargs -I % bash -c 'grep -v % Build'
Thus the question: how does one list the *.cpp files that are not present in the Build file using shell commands? I can do something like this, bug this is ugly:
ls *.cpp | perl -e 'while(<>){chomp;my $l=`grep $_ Build`;chomp $l;if(length $l==0){print("rm $_\n");}}'
More specifically, I'd like to remove *.cpp files not listed in Build
You want comm or join to join two sorted lists together. I always mix comm arguments, but I think:
comm -23 <(find . -type f -name '*.cpp' | sort) <(sort Build) |
xargs -n '\n' echo rm
or if you want to depend on filename expansion:
shopt -s nullglob # at least
comm -23 <(printf "%s\n" *.cpp | sort) <(sort Build) | ...
Do not parse `ls.
The <(...) is bash specific process substitution. In non-bash shell just create a temporary file with the output of processes.
GNU grep already offers you this possibility with the -f switch:
printf '%s\n' *.cpp | grep -F -x -v -f Build
-F: no regex
-x: full-line match
-v: invert (not match)
-f: any of the line in Build
In other words: filter out any line in Build

Is there a script to compress every single file in a directory and ouput it to another Directory?

So I'm looking to compress the files in a given directory, for example /etc/input and output the files in /etc/output, and it should be like:
$ ls /etc/input
file1
file2
file3
$ script.sh
$ ls /etc/output
file1.zip
file2.zip
file3.zip
$ ls /etc/input
For now, what i wrote looks like this:
find . -type f -print | while read fname ; do
mkdir -p "../output/`dirname \"$fname\"`"
gzip -c "$fname" > "../output/$fname.gz"
done
You could use find, but I think it's simpler with pure Bash.
INPUT=/etc/input
OUTPUT=/etc/output
mkdir -p "$OUTPUT"
for file in "$INPUT"/* ; do
gzip -c "$file" > "${OUTPUT}/${file}.gz"
done
Change INPUT and OUTPUT to match what you want.

Bash looping over files in different directories and print output

I have *.vcf, *.vcf.vcfidx and *.vcf.idx files in directory /mypath/mydir/. I want to loop over .vcf files only using command below (for file 1):
command for one vcf file:
vcf-subset -c sample.txt vcffile1.vcf | bgzip -c > output_vcfile1.vcf_.vcf.gz
Can someone please help loop over all the .vcf (not vcf.vcfidx or vcf.idx) files and get the output for each file in designated directory /get/inthis/dir/ using the command shown above?
Just use glob pattern *.vcf:
for i in *.vcf; do echo "$i"; done
The glob pattern *.vcf will match only files ending in .vcf.
Your command:
for i in *.vcf; do
vcf-subset -c sample.txt "$i" | bgzip -c > /get/inthis/dir/output_"$i"_.vcf.gz
done
If you have to search for .vcf files in a specific directory e.g. /foo/bar/, do:
for i in /foo/bar/*.vcf; do
vcf-subset -c sample.txt "$i" | bgzip -c > /get/inthis/dir/output_"${i##*/}"_.vcf.gz
done

Copy file to file from a list of pair of text

My file includes:
a.txt b.txt
c.txt d.txt
e.txt f.txt
Want to do cp a.txt b.txt , cp c.txt d.txt, cp e.txt f.txt
What is the quick oneliner to do this ?
I try cat file | xargs -I{} cp {}. but it does not work since it treats the whole thing as one argument.
Please don't call your file file!
cat list | xargs -n 2 cp
Here the switch -n 2 is crucial: it tells xargs to use at most 2 arguments per line.
Why not a regular loop?
while read -r file1 file2 ; do
cp -- "$file1" "$file2";
done < file

xargs respect wildcards in searches

I have a file called file1.txt:
dir1
dir2
dir3
...
I wanted to use xargs to check if some files exist farther into the file system like this:
cat file1.txt | xargs -i ls /projects/analysis7/{}/meta_bwa/hg19a/*varFilter 2>/dev/null
But xargs never seems smart enough to expand the *. ie, it never finds the files even when they would match the pattern (if the * was expanded).
Any ideas?
You just need to add sh -c:
cat file1.txt | xargs -i sh -c 'ls /projects/analysis7/{}/meta_bwa/hg19a/*varFilter' 2>/dev/null

Resources