TL;DR
I'm trying to write a simple script that compiles all .swift
files in a given folder and any of it's subfolders, but which excludes those files that start with a shebang.
The Details
I'm trying to write a simple utility that will let me compile multiple Swift files into a single compiled output without requiring any advanced IDEs or project files, etc. The folder structure itself will be the project's definition with the root being wherever I find a main.swift
file.
Assuming I've already found main.swift
and am in the according directory, starting with the find
command, I can find all relevant Swift files like so...
find * -type f -name "*.swift"
Thanks to another answer here, by appending -print0
and feeding that to xargs -0
, they can all be sent to swift compiler in one fell swoop, like so...
find * -type f -name "*.swift" -print0 | xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"
Note: thanks to the use of
-print0
on thefind
command andxargs -0
on the other side, all n arguments are passed in at the same time to one execution ofxcrun
, not n executions ofxcrun
with one argument each. There is only one compilation and one single output file.
The issue is if any of those Swift files are set up as Swift script files (i.e. those that start with a shebang), the compiler rejects them. They're also most likely to contain top-level statements, something the compiler also doesn't like unless they are in main.swift
.
For instance, if this is in the file someutil
...
#! /usr/bin/env swift
print("Hello from Swift!")
...and you ran chmod x someutil
, you could now execute that Swift file like any other shell script so long as it's reachable in the path.
echo Here we go!
someutil
echo Done!
Output
Here we go!
Hello from Swift
Done!
However, if you send that file to the compiler, it will complain both about the shebang and about the top-level statements not being in main.swift
.
As such, I'm trying to filter out any of the found files which start with a shebang, using that basically as the identifier of Swift scripts to be excluded.
I've seen a lot of grep tutorials for how to include only those files, but can't find any that exclude them, especially since the above code also depends on the -print0
of the find command itself (meaning I can't easily do the filtering elsewhere.)
So is this possible?
CodePudding user response:
May be with a grep
command between find
and xcrun
:
find * -type f -name "*.swift" -print0 | xargs -0 grep -L '^#! /usr/bin/env swift$' -Z | xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"
grep
option:
-L
: Suppress normal output; instead print the name of each input file from which no output would normally have been printed-Z
: Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name.
CodePudding user response:
You can run a loop with output of find
command and run a grep
inside:
while IFS= read -rd '' f; do
grep -qF '#! /usr/bin/env swift' "$f" || printf '%s\0' "$f"
done < <(find * -type f -name "*.swift" -print0) |
xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"