4 ms·
Yes, it's not particularly difficult either, as long as you have the appropriate tools installed. csvjson path/to/infile.csv \ | jq -c ".[]" \
by JoshuaDavid 6y ago
Yes, it's not particularly difficult either, as long as you have the appropriate tools installed.
csvjson path/to/infile.csv \
| jq -c ".[]" \
| while read LINE; do
UNAME="$(echo "$LINE" | jq -r ".uname")";
CNAME="$(echo "$LINE" | jq -r ".cname")";
if id -u "$UNAME" &> /dev/null; then
# Find processes with this command name belonging to this user
comm -12 <(ps -C "$CNAME" -o "pid=" | sort) <(ps -U "$UNAME" -o "pid=" | sort) | \
while read PID; do
# rss=Resident Set Size, i.e. the amount of memory this process is currently
# using, not including swap. You might want vsize instead, depending on your needs.
RSS="$(ps -o "rss=" "$PID")";
STARTISODATE="$(date --date="$(ps -o "lstart=" "$PID")" --iso-8601="seconds")";
# If you actually plan to use this you need to make sure pid isn't anything important
kill "$PID";
jq -n -c \
--argjson "pid" "$PID" \
--argjson "rss" "$RSS" \
--arg "start" "$STARTISODATE" \
--arg "command" "$CNAME" \
--arg "username" "$UNAME" \
'{"pid":$pid,"memory_kb":$rss,"start":$start,"command":$command,"username":$username}';
done
else
# Print an error to stdout if the user does not exist
echo "warning: user $UNAME does not exist" >&2
fi
done \
| jq -s 'sort_by(.memory_kb)' \ # sort_by(-.memory_kb) if you want it in descending order
| in2csv --format=json \
> path/to/outfile.csv
I'm guessing you meant "parse the CSV correctly using only bash", and I agree that's difficult, which is why you should not do that. Instead, you should use a tool that has been specifically designed to do that one task, and do it well (in this case, that task is "convert a csv into a format that's easier to work with, namely json"). This is the unix way.
How extensible is PowerShell? With bash, you can write a new command that takes text input in a certain format and produces text output in a certain format, in whatever language you want, and plug it in in the appropriate place in the pipeline. Is the same true of PowerShell?
- jiggawatts 6y agoI am properly impressed. Wow! Most people I give this challenge to fail to account for the complexities of even a simple format like CSV, and typically simply use "grep" to find processes, which would cause havoc with simple user names like "Bob Ash = bash". For comparison, the equivalent in PowerShell is this: #require -RunAsAdministrator $i = ConvertFrom-Csv @' UserName,ProcessName DOMAIN\BobJones,explorer DOMAIN\Bash,notepad '@ $ps = Get-Process -IncludeUserName Compare-Object $ps $i -PassThru -Property UserName,ProcessName -ExcludeDifferent -IncludeEqual ` | Stop-Process -PassThru ` | Sort-Object PeakWorkingSet64 -Descending ` | Select-Object ` ProcessName, ` PeakWorkingSet64,` @{ Name='StartDate'; Expression={ '{0:o}' -f $_.StartTime } } ` | ConvertTo-Csv Note that it's easy to substitute "Import-Csv" and "Export-Csv" to deal with CSV files instead of CSV formatted text. It's also a trivial extension to convert this snippet into a "ps1" script that can take formal parameters as input from anything that has those two columns, not just CSVs. And those parameters can be invoked manually, validated by the engine (not code!), and so forth. What I hope this PowerShell version shows off is just how "neat" it is compared to bash. It's just a pipeline of little processing commands: "get,compare,stop,sort,select,convert". As impressive as your bash solution is, it's... messy. You were forced to write manual loops, use JSON for processing CSV, and do all sorts of admittedly pretty fancy trickery. Ask yourself: Could a junior tech make changes to your script and not break it? Could they even read it? I know I certainly couldn't, and I know more than a little bash! As to how extensible PowerShell is: More than bash! The "shell API" is just a byte stream in, and a bunch of byte streams out. That's it. The PowerShell API is very rich, but it's also very easy to get started. You can simply write scripts or write a "binary module" in any .NET language such as C#. Simply derive from the System.Management.Automation.Cmdlet class, override the processing methods as required, and start writing code. The PowerShell engine will take care of things for you like hooking up input parameters, matching wild cards, expanding file paths, validating inputs, generating error messages in the user's OS language, etc... In my experience, I can write a "proper" command line tool with all the bells & whistles using C/C++ in about a few thousand lines of code. With modern command-line parsing libraries, it's about 500 lines if I'm lucky. Meanwhile, it's possible to build the equivalent using PowerShell and C# in about 50 lines, of which 40 is just generic C# class boilerplate.
- 6y ago