4 ms·
I think the OP is mostly talking about "perl one liners" on the shell like this: https://catonmat.net/ftp/perl1line.txt https://catonmat.net/ftp/perl1line.txt
by esaym 6y ago
I think the OP is mostly talking about "perl one liners" on the shell like this: https://catonmat.net/ftp/perl1line.txt https://catonmat.net/ftp/perl1line.txt
It is not that hard either (unless perl is completely foreign to you).
Ironically just today I wrote a python script (using concurrent.futures) to batch re-encode 10gb of mp3 podcasts into 3gb of opus files to save space. Before I deleted the old mp3's, I did a quick file count of mp3 and opus files only to have 5 extra opus files... I beat my head really good trying to glue a bunch of bash stuff together but I could not find where the 5 extra opus files were coming from.
I defected back to perl. All I needed was an alphabetical list of all the files (there were many sub-directories), perfect for a little perl oneliner:
find /podcasts/ -iname "* \.ogg" | perl -nle 'if( $_ =~ /\/([\w-]+.\w\w\w)$/) { print "$1"}' | sort >ogg.txt
I did the same thing for * .mp3 files and then diffed the two files. I quickly noticed the extra 5 opus files were from me doing test encodes a couple of weeks ago that I forgot about.
Sure it looks hideous, but the explanation is easy: for 'perl -nle', the 'l' means process each line from stdin individually, the 'n' means no auto printing of the line, and the 'e' is basically the perl 'one liner' mode. Either way, each line comes in and is stored in '$_', I use a capturing regex to grab the file name without parent directory names, basically everything after the last '/' in a path that ends with a three letter extension (\w\w\w). The "captured" part of the regex ends up in '$1'. Also see 'perldoc run' for all the runtime one liner options.
- high_priest 6y agoWhy am I not surprised that the PERL part could be solved with bash in the same space. Why are you so eager to use lang on top of lang, in such simple cases?
- esaym 6y agoFeel free to demonstrate. Take a long path with nasty characters and give me the ending file name. I want "track1.mp3" returned from: /podcast/with/nasty'--c h a r$/and/stuff/track1.mp3
- AareyBaba 6y ago$ basename "/podcast/with/nasty'--c h a r$/and/stuff/track1.mp3" track1.mp3
- thezilch 6y ago$ path="/podcast/with/nasty'--c h a r$/and/stuff/track1.mp3" $ echo "${path##*/}" track1.mp3 $ basename "${path}" track1.mp3 $ echo "${path}" | awk -F/ '{print $NF}' track1.mp3
- zimpenfish 6y agoIf you have that in a variable, which you presumably would if you're reading them one at a time, you can use "remove longest matching prefix" substitution. $ i="/podcast/with/nasty'--c h a r$/and/stuff/track1.mp3" $ echo "${i##*/}" track1.mp3 [Edit: 'thezilch beat me too it by a couple of minutes]
- Jare 6y agoYou still get +1 for providing a pointer to the explanation while remaining clear and succinct.
- sergeykish 6y agoThis part is really cryptic, I would prefer $ function remove_longest_matching_prefix () { echo "${1##$2}"; } $ remove_longest_matching_prefix "$i" '*/' track1.mp3 awk -F/ accepts stream as in perl example
- ubercow13 6y agoIn zsh it would be echo “${uglypath:t}”
- deleted 6y ago[deleted]
- zimpenfish 6y agoIf I've not wildly misunderstood what you're doing with that line (and apologies if I have), could you not just stick `-printf '%f\n'` on the end of the `find` command? (By definition, since you're looking for `.ogg` files, everything `find` finds will have a path that ends in a three letter extension.)
- esaym 6y agoAh, that is a good one! I've never even messed with the -prinf options.
- zimpenfish 6y agoIt's one of those things that's immensely helpful but difficult to discover organically, I think, since a lot of people will go "find outputs this, now I pipeline to transform that, this is The Unix Way" and never realise that `find` can do a bunch of transforms for you for free.
- sergeykish 6y agoIt would be simpler (and match "everything after the last '/'") with perl -nle 'if( $_ =~ /([^\/]+)$/) { print "$1"}' I don't quite get how can stream of '* \.ogg' proceed through /[\w-]+.\w\w\w$/ filter. Notice space. And it allows ",ogg" (dot not escaped so it is not extension), thankfully find provides /\.ogg$/
- esaym 6y agoSpace was because HN uses it as italics and I don't know the escape. And yes there are cleaner ways, but the point was a real world example of having something not work out in pure shell but yet quickly barfing out something working with perl. And yes, looks like I didn't escape the dot, funny!
- sergeykish 6y agoGot it. Sure, I like one liners and I like piping. Ruby is strongly influenced by Perl: $ find . -iname '*.ogg' | ruby -nle 'puts $1 if $_ =~ /\/([\w-]+\.\w\w\w)$/' I think the reason people badmouth Perl is because it is safe. People claim PHP improved but all I can see is language without design. JavaScript has lots of bad parts and we should not talk about them. I like AWK matchers though not its functions. I am not familiar with Perl but it is designed.
- gray_-_wolf 6y agoOr, in actual posix compatible way: find /tmp/test -type f -iname '*.ogg' -exec sh -c 'for f; do printf "%s\n" "${f##*/}"; done' - {} +