Hvad er din seneste nyttige Perl one-liner (eller et rør, der involverer Perl)?

One-liner:

  • løse en real-world problem
  • ikke være grundigt kryptisk (skal være let at forstå og reproducere)
  • være værd at den tid, det tager at skrive det (bør ikke være for klog)

Jeg er på udkig efter praktiske tips og tricks (supplerende eksempler for perldoc perlrun).

“sidste”: “endelige”, som i, at jeg aldrig ville skrive en anden igen. Der kommer ikke til at ske. Jeg vil holde skrive Perl one-liners, så længe hurtig accepterer det. Måske du mente “seneste”.
Tak skal du have. Jeg har rettet titlen. Tid til mit sidste måltid er ikke kommet endnu 🙂

OriginalForfatteren jfs | 2008-09-21

24 svar

  1. 11

    Du ikke kan tænke på dette som Perl, men jeg bruger ack religiøst (det er en smart grep udskiftning skrevet i Perl), og som lader mig med at redigere, for eksempel, alle mine Perl-tests, som er inkluderet i en bestemt del af vores API:

    vim $(ack --perl -l 'api/v1/episode' t)

    Som en side bemærkning, hvis du bruger vim, kan du kør alle tests i din editor ‘ s buffere.

    For noget med mere indlysende (hvis der er simpelt Perl, jeg havde brug for at vide, hvor mange test programmer, der bruges out test fixtures i t/lib/TestPM bibliotek (jeg har skåret ned på kommandoen for klarhed).

    ack $(ls t/lib/TestPM/|awk -F'.' '{print $1}'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

    Bemærk, hvordan “deltag”, som viser resultaterne i en regex foder til ack.

    OriginalForfatteren Ovid

  2. 11

    Problemet: En media player ikke automatisk indlæse undertekster på grund af deres navne afviger fra tilsvarende video filer.

    Løsning: Omdøbe alle *.srt (filer med undertekster) til at matche *.avi (filer med video).

    perl -e'while(<*.avi>) { s/avi$/srt/; rename <*.srt>, $_ }'

    ADVARSEL: Sortering af originale video og undertekst filnavne skal være den samme.

    Her, at få en mere detaljeret version af ovenstående one-liner:

    my @avi = glob('*.avi');
    my @srt = glob('*.srt');
    
    for my $i (0..$#avi)
    {
      my $video_filename = $avi[$i];
      $video_filename =~ s/avi$/srt/;   # 'movie1.avi' -> 'movie1.srt'
    
      my $subtitle_filename = $srt[$i]; # 'film1.srt'
      rename($subtitle_filename, $video_filename); # 'film1.srt' -> 'movie1.srt'
    }

    OriginalForfatteren jfs

  3. 11

    Blæksprutte log filer. De er store, er de ikke? Bortset fra som standard har de sekunder-fra-den-epoke som den tid felt. Her er en one-liner, der læser fra en blæksprutte log fil, og konverterer den til en læsbar dato:

    perl -pe's/([\d.]+)/localtime $1/e;' access.log

    Med et lille tweak, kan du gøre det til kun at vise linjer med et søgeord, du er interesseret i. Følgende ure til stackoverflow.com adgang til og udskriver kun dem, der er linjer, med en læsbar dato. For at gøre det mere nyttigt, jeg giver det output af tail -f, så jeg kan se adgang i realtid:

    tail -f access.log | perl -ne's/([\d.]+)/localtime $1/e,print if /stackoverflow\.com/'

    OriginalForfatteren pjf

  4. 9

    Den fælles formsprog for at bruge find ... -exec rm {} \; til at slette et sæt af filer et sted i en mappe-træet er ikke særligt effektiv i, at det udfører den rm kommandoen én gang for hver fil fundet. En af mine vaner, der er født fra de dage, hvor computere var ikke helt så hurtig (dagnabbit!), er til at erstatte mange opkald til rm med en opfordring til perl:

    find . -name '*.whatever' | perl -lne unlink

    Den perl en del af kommando-linje lyder en liste over filer, der udsendes* ved find, en per linie, trim den newline off, og sletter filen ved hjælp af perl ‘ s indbyggede unlink() funktion, som tager $_ som sit argument, hvis ikke eksplicit argument er leveret. ($_ er indstillet til hver linje i input tak til -n flag.) (*I disse dage, de fleste find kommandoer gøre -print som standard, så jeg kan overlade en del ud.)

    Jeg kan lide denne formsprog, der ikke kun på grund af den effektivitet (muligvis er mindre vigtigt i disse dage), men også fordi den har færre chorded/akavet taster, end at skrive den traditionelle -exec rm {} \; sekvens. Man undgår også at citere problemer forårsaget af filnavn med mellemrum, citater osv., som jeg har mange. (En mere robust version kan bruge find‘s -print0 indstilling og derefter bede perl til at læse null-afgrænset poster i stedet for linjer, men jeg er normalt temmelig sikker på, at min filnavnene må ikke indeholde indlejrede linjeskift.)

    Jeg har brugt xargs til at løse dette problem fra en tid, før Perl var et glimt i Larry ‘ s eye :-).

    OriginalForfatteren John Siracusa

  5. 7

    Alle one-liners fra de svar, der er indsamlet på ét sted:

    • perl -pe's/([\d.]+)/localtime $1/e;' access.log

    • ack $(ls t/lib/TestPM/|awk -F'.' '{print $1}'|xargs perl -e 'print join "|" => @ARGV')
      aggtests/t -l

    • perl -e'while(<*.avi>) { s/avi$/srt/; rename <*.srt>, $_ }'

    • find . -name '*.whatever' | perl -lne unlink

    • tail -F /var/log/squid/access.log | perl -ane 'BEGIN{$|++} $F[6] =~ m{\Qrad.live.com/ADSAdClient31.dll}
      && printf "%02d:%02d:%02d %15s %9d\n", sub{reverse @_[0..2]}->(localtime $F[0]), @F[2,4]'

    • export PATH=$(perl -F: -ane'print join q/:/, grep { !$c{$_}++ } @F'<<<$PATH)

    • alias e2d="perl -le \"print scalar(localtime($ARGV[0]));\""

    • perl -ple '$_=eval'

    • perl -00 -ne 'print sort split /^/'

    • perl -pe'1while+s/\t/" "x(8-pos()%8)/e'

    • tail -f log | perl -ne '$s=time() unless $s; $n=time(); $d=$n-$s; if ($d>=2) { print qq
      ($. lines in last $d secs, rate ),$./$d,qq(\n); $. =0; $s=$n; }'

    • perl -MFile::Spec -e 'print join(qq(\n),File::Spec->path).qq(\n)'

    Se tilsvarende svar til deres beskrivelser.

    OriginalForfatteren

  6. 6

    Perl one-liner jeg bruger mest, er Perl lommeregner

    perl -ple '$_=eval'
    Hvis du kører Perl 5.10, at du kan køre perl -plE ‘$_=eval”, for at 5.10 funktioner.

    OriginalForfatteren

  7. 4

    En af de største båndbredde hogs på $arbejde er at downloade web reklame, så jeg kigger på de lavt-hængende frugter som venter på at blive plukket. Jeg har sluppet af Google-annoncer, jeg nu har Microsoft i min serie af seværdigheder. Så kører jeg en hale på log-fil, og udvælge de linjer, der er af interesse:

    tail -F /var/log/squid/access.log | \
    perl -ane 'BEGIN{$|++} $F[6] =~ m{\Qrad.live.com/ADSAdClient31.dll}
        && printf "%02d:%02d:%02d %15s %9d\n",
            sub{reverse @_[0..2]}->(localtime $F[0]), @F[2,4]'

    Hvad Perl-rør gør, er at begynde med at indstille autoflush til true, så at enhver, der er handlet på, er printet ud med det samme. Ellers output det chunked op, og man får en batch af linjer, når output-buffer fylder. -Et skifte opdeler hver input line på hvid plads, og gemmer resultaterne i arrayet @F (funktionalitet inspireret af awk ‘ s kapacitet til at opdele input poster i sin $1, $2, $3… variabler).

    Det kontrollerer, om den 7-feltet i den linje, der indeholder URI vi søger (ved hjælp af \Q for at gemme os den smerte, for at undslippe uinteressant metategn). Hvis der findes et match, er det temmelig-udskriver tidspunktet, kilde-IP-adresse og det antal byte, der er vendt tilbage fra den eksterne site.

    Den tid, der er opnået ved at tage den epoke tid i det første felt og bruge “localtime” for at bryde det ned i dets komponenter (time, minut, sekund, dag, måned, år). Det tager en bid af de første tre elementer retur, sekund, minut og time, og vender for at få time, minut og sekund. Dette er returneret som en tre-element-array, sammen med en skive af den tredje (IP-adresse) og femte (størrelsen) fra den oprindelige @F-række. Disse fem argumenter er gået til sprintf hvilke formater resultaterne.

    OriginalForfatteren dland

  8. 4

    @dr_pepper

    Fjerne bogstavelig dubletter i $PATH:

    $ export PATH=$(perl -F: -ane'print join q/:/, grep { !$c{$_}++ } @F'<<<$PATH)

    Print unikke rene stier fra %PATH% miljø-variabel (det behøver ikke røre ../ og ens, erstatte File::Spec->rel2abs af Cwd::realpath, hvis det er ønskeligt) Det er ikke en one-liner til at være mere bærbare:

    #!/usr/bin/perl -w
    use File::Spec; 
    
    $, = "\n"; 
    print grep { !$count{$_}++ } 
          map  { File::Spec->rel2abs($_) } 
          File::Spec->path;
    Tak for at vise mig det, jeg var på udkig efter en kortere one-liner til at gøre dette. I mit miljø, hvide rum er den separator, når du bruger små bogstaver $path. Er det bedre at bruge store bogstaver $PATH?
    I min shell (bash) $path, og $PATH er forskellige variabler (navne er bogstaver: $ a=2; A=3; echo $(($ * , $A)) print ‘6’.
    Dubletter kan fjernes ved hjælp af en kombination af programmer,tr, sort, uniq, cut og et rør.
    Men, ved hjælp af tr, form, etc ændringer vejen for, og som kan forårsage uønskede bivirkninger.
    I ZSH variablen path er bundet af den variable PATH, så PATH er altid elementer af path, sammen med et kolon, og path er altid et array, der indeholder bidder af PATH delt af en kolonne. For at gøre dem unikke, bare anvende -U modifier til en af de variabler: skrift -U STI

    OriginalForfatteren jfs

  9. 3

    I svar til Ovids vim/ack kombination:

    Også jeg ofte søger efter noget, og derefter ønsker at åbne matchende filer i Vim, så jeg lavede mig en lille genvej for noget tid siden (virker i ZSH eneste, tror jeg):

    function vimify-eval; {
        if [[ ! -z "$BUFFER" ]]; then
            if [[ $BUFFER = 'ack'* ]]; then
                BUFFER="$BUFFER -l"
            fi  
            BUFFER="vim  \$($BUFFER)"
            zle accept-line
        fi  
    }
    
    zle -N vim-eval-widget vimify-eval
    
    bindkey '^P' vim-eval-widget

    Det fungerer sådan her: jeg søger noget hjælp ack, som ack some-pattern. Jeg ser på resultaterne, og hvis jeg kan lide det, jeg trykker på pil-op for at få ack-line igen, og tryk derefter på CTRL+P., Hvad sker der så, at ZSH og føjer “-l” for notering filnavne kun, hvis den kommando, der starter med “ack”. Derefter sætter det “$(…)” rundt på kommando og “vim” foran det. Så det hele er udført.

    OriginalForfatteren jkramer

  10. 3

    Jeg bruge dette ganske ofte til hurtigt at konvertere epoch times nyttige datomærker.

    perl -l -e 'print scalar(localtime($ARGV[0]))'

    Lave et alias i din shell:

    alias e2d="perl -le \"print scalar(localtime($ARGV[0]));\""

    Så rør en epoke nummer til alias.

    echo 1219174516 | e2d

    Mange programmer og værktøjer på Unix/Linux bruge epoke værdier til at repræsentere en gang, så det har vist sig at være uvurderligt for mig.

    For at få en læsbar datomærke fra epoke sekunder, kan du også bruge GNU date med @ – tegnet: date –[email protected]

    OriginalForfatteren jtimberman

  11. 3

    Fjerne dubletter i path-variabel:

    set path=(`echo $path | perl -e 'foreach(split(//,<>)){print $_," " unless $s{$_}++;}'`)
    Hvad er en separator mellem stier i $path? Se mit svar.

    OriginalForfatteren dr_pepper

  12. 3

    Fjerne MS-DOS-line-endelser.

    perl -p -i -e 's/\r\n$/\n/' htdocs/*.asp
    1. -i kræver et suffiks, fx, -i.bak. 2. Det vil ikke arbejde på Windows.
    Jeg var spekulerer på, hvordan at gøre Perl pie i Windows. Tak for tip.

    OriginalForfatteren JDrago

  13. 3

    Jeg ofte brug for at se en læsevenlig version af den bane, mens shell scripting. Følgende one-liners, der udskrives på hver sti indlæg på sin egen linje.

    Over tid er denne one-liner har udviklet sig gennem flere faser:

    UNIX (version 1):

    perl -e 'print join("\n",split(":",$ENV{"PATH"}))."\n"'

    Windows (version 2):

    perl -e "print join(qq(\n),split(';',$ENV{'PATH'})).qq(\n)"

    Både UNIX/Windows (ved brug af q/qq tip fra @j-f-sebastian) (version 3):

    perl -MFile::Spec -e 'print join(qq(\n),File::Spec->path).qq(\n)' # UNIX
    perl -MFile::Spec -e "print join(qq(\n),File::Spec->path).qq(\n)" # Windows
    perl -MFile::Spec -E '$,=qq(\n); say File::Spec->path'
    perl -MFile::Spec::Functions -E '$,=qq(\n); say path'
    Sebastian: Når du kører med -E jeg får Unrecognized switch: -E (-h will show valid options). på både Windows og UNIX. Jeg kører perl-v5.8.8 på begge platforme.
    -E giver ekstra funktioner såsom say() fra 5.10 (siden 2007).
    Sebastian: Tak, der er en nyttig tidbit!

    OriginalForfatteren Tim Lewis

  14. 3

    Udvinding Stack Overflow ry uden at skulle åbne en web-side:

    perl -nle "print '  Stack Overflow        ' . $1 . '  (no change)' if /\s{20,99}([0-9,]{3,6})<\/div>/;" "SO.html"  >> SOscores.txt

    Dette forudsætter, at brugeren side allerede er blevet downloadet til fil SO.html. Jeg bruger wget til dette formål. Den notation, der her er til Windows command line; det ville være lidt anderledes for Linux eller Mac OS X. Det output, der er knyttet til en tekst fil.

    Jeg bruge det i en BAT script til automatisk prøvetagning af omdømme på fire lokaliteter i familien:
    Stack Overflow, Server Fejl, superbruger og Meta Stack Overflow.

    OriginalForfatteren Peter Mortensen

  15. 2

    En af de seneste one-liners, der fik en plads i min ~/bin:

    perl -ne '$s=time() unless $s; $n=time(); $d=$n-$s; if ($d>=2) { print "$. lines in last $d secs, rate ",$./$d,"\n"; $. =0; $s=$n; }'

    Du vil bruge det mod en hale af en log-fil, og det vil udskrive sats af strækninger, der er outputed.

    Ønsker at vide, hvor mange rammer per sekund, du får på din webservere? tail-f log | this_script.

    Det er en mini-pipe viewer (pv) <ivarch.com/programs/pv.shtml>. Men din one-liner virker på Windows.

    OriginalForfatteren melo

  16. 2

    Filtre en strøm af white-space adskilt strofer (navn/værdi par lister),
    sortering hver strofe individuelt:

    perl -00 -ne 'print sort split /^/'
    sort() vil sætte tomme linjer på stk ‘ s top. Jeg gætte, du rent faktisk mener dette: perl -00 -ne'($n, @a) = sorter split /^/; print @a $n’ Både one-liners vil mislykkes, hvis der ikke er nogen newline efter sidste afsnit.

    OriginalForfatteren mtk

  17. 2

    Netværksadministratorer har tendens til at misconfigure “subnet adresse” som “host address” især mens du bruger Cisco ASDM auto-suggest. Dette enkle one-liner scanninger konfigurationsfiler for en sådan konfiguration fejl.

    forkert brug: permit host 10.1.1.0

    korrekt brug: permit 10.1.1.0 255.255.255.0

    perl -ne "print if /host ([\w\-\.]+){3}\.0 /" *.conf

    Dette blev testet og bruges på Windows, kan du foreslå, hvis det skal ændres på nogen måde for korrekt brug.

    OriginalForfatteren Benny

  18. 1

    Udvide alle faner til rum: perl -pe'1while+s/\t/" "x(8-pos()%8)/e'

    Selvfølgelig, dette kan gøres med :angiv et, :ret i Vim.

    perl -pe’1while+s/\t/” “x(8-(pos)%8)/e’ Parentes er påkrævet.

    OriginalForfatteren ephemient

  19. 1

    Jeg har en liste af tags som jeg identificere dele af teksten. Master listen er i formatet:

    text description {tag_label}

    Det er vigtigt, at {tag_label} er ikke kopieres. Så der er det rart simpelt script:

    perl -ne '($c) = $_ =~ /({.*?})/; print $c,"\n" ' $1 | sort  | uniq -c | sort -d

    Jeg ved, at jeg kunne gøre det hele meget i skallen, eller perl, men dette var den første ting, der kom til at tænke på.

    perl -ne'$f{$1}++ while /({.*?})/g; END{ print "$f{$_} $_\n" for (sort {$f{$a} <=> $f{$b}} keys %f) }' $1. Du har ret i, at for sådanne opgaver, er den første ting i tankerne, er godt nok. btw, er du sikker på, at der kun kunne være ét tag per linje?

    OriginalForfatteren singingfish

  20. 1

    Ofte har jeg haft til at konvertere tabeldata i at konfigurationsfiler. Til e.g, netværkskabler leverandører levere lappe rekord i Excel-format, og vi er nødt til at bruge disse oplysninger til at oprette konfigurationsfiler. jeg.e,

    Interface, Connect to, Vlan
    Gi1/0/1, Desktop, 1286
    Gi1/0/2, IP Phone, 1317

    bør blive:

    interface Gi1/0/1
     description Desktop
     switchport access vlan 1286

    og så videre. Den samme opgave igen i flere former i forskellige administrative opgaver, hvor en tabular data skal indledes med deres område navn og omsat til en flad struktur. Jeg har set nogle af DBA ‘ s spilde en masse tid ved at forberede deres SQL-sætninger fra excel ark. Det kan opnås ved hjælp af denne simple one-liner. Bare gemme det tabulære data i CSV-format ved hjælp af din foretrukne regneark værktøj og køre denne one-liner. Felt navne i header-rækken bliver indsat til enkelte celle værdier, så du kan redigere det til at matche dine krav.

    perl -F, -lane "if ($.==1) {@keys = @F} else{print @keys[$_].$F[$_] foreach(0..$#F)} " 

    Den advarsel er, at ingen af de feltnavne, eller værdier, der bør indeholde kommaer. Måske kan dette blive uddybet for at fange sådanne undtagelser i en en-linje, venligst forbedre denne, hvis det er muligt.

    OriginalForfatteren Benny

  21. 0

    Her er én, som jeg finder smart, når beskæftiger sig med en samling komprimeret log-filer:

       open STATFILE, "zcat $logFile|" or die "Can't open zcat of $logFile" ;
    One-liner betyder, at et helt program på en linie, ikke et nyttigt linje i et program.
    Jeg ville faktisk adskilt dette i 2 eller flere linier mig selv.

    OriginalForfatteren Kwondri

  22. -5

    På et tidspunkt fandt jeg, at noget af det, jeg ønsker at gøre med perl, der er kort nok til at ske på kommando linje med ‘perl -e’ kan gøres bedre, lettere og hurtigere med normale funktioner ZSH uden besværet med at citere. E. g. ovenstående eksempel kunne gøres således:

    for foo in *.avi; mv *.srt ${foo:r}.srt

    OPDATERING

    Den onliner ovenfor er obiously forkert, sorry for ikke at læse omhyggeligt. Her er den rigtige version:

    srt=(*.srt); for foo in *.avi; mv $srt[1] ${foo:r}.srt && srt=($srt[2,-1])
    Du misforstår perl. ≪*.srt>, er en iterator, der returnerer et af .srt filer, hver gang gennem den ydre sløjfe.
    Undskyld, min fejl, jeg burde virkelig læse mere omhyggeligt. Jeg vil lave, at der i svaret.
    glob-i-skalar-forbindelse er virkelig virkelig nemt at komme galt; det bør undgås hvor det er muligt.
    Ikke den nye version kommer ud af sync på en mv fiasko?
    Godt, hele ideen med denne ting er noget ustabilt, da det antages, at for hver .avi er der en .srt, og at både, når sorteret alfabetisk, og har hver avi/srt par på samme position i listen. Du kan dog erstatte && med ; og sætte parenteser omkring det. 😉

    OriginalForfatteren jkramer

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *