Wat is het gebruik van noop [:] in bash?

Ik zocht naar noop in bash (:), maar kon geen goede informatie vinden. Wat is het exacte doel of gebruik van deze operator?

Ik heb geprobeerd te volgen en het werkt als volgt voor mij:

[mandy@root]$ a=11
[mandy@root]$ b=20
[mandy@root]$ c=30
[mandy@root]$ echo $a; : echo $b ; echo $c
10
30

Laat het me weten, elk gebruik van deze operator in realtime of elke plaats waar het verplicht is om het te gebruiken.


Antwoord 1, autoriteit 100%

Het is er meer om historische redenen. De ingebouwde dubbele punt :is exact gelijk aan true. Het is traditioneel om truete gebruiken wanneer de retourwaarde belangrijk is, bijvoorbeeld in een oneindige lus:

while true; do
  echo 'Going on forever'
done

Het is traditioneel om :te gebruiken wanneer de shell-syntaxis een commando vereist, maar je niets te doen hebt.

while keep_waiting; do
  : # busy-wait
done

De :ingebouwde dateert helemaal terug naar de Thompson shell, het was aanwezigin Unix v6. :was een labelindicator voor de goto-instructie van de Thompson-shell. Het label kan elke tekst zijn, dus :verdubbelde als commentaarindicator (als er geen goto commentis, dan is : commentin feite een opmerking). De Bourne-shellhad geen gotomaar hield :.

Een algemeen idioom dat :is : ${var=VALUE}, die varinstelt op VALUEals het niet was ingesteld en niets doet als varstond al vast. Deze constructie bestaat alleen in de vorm van een vervanging van een variabele, en deze vervanging van een variabele moet op de een of andere manier deel uitmaken van een opdracht: een no-op-opdracht werkt goed.

Zie ook Waarvoor dient de ingebouwde dubbele punt?.


Antwoord 2, autoriteit 15%

Ik gebruik het voor if-statements als ik commentaar geef op de hele code. U heeft bijvoorbeeld een toets:

if [ "$foo" != "1" ]
then
    echo Success
fi

maar je wilt tijdelijk een opmerking plaatsen over alles wat erin staat:

if [ "$foo" != "1" ]
then
    #echo Success
fi

Waardoor bash een syntaxisfout geeft:

line 4: syntax error near unexpected token `fi'
line 4: `fi'

Bash mag geen lege blokken (WTF) hebben. Dus je voegt een no-op toe:

if [ "$foo" != "1" ]
then
    #echo Success
    :
fi

of je kunt de no-op gebruiken om commentaar te geven op de regels:

if [ "$foo" != "1" ]
then
    : echo Success
fi

Antwoord 3, autoriteit 7%

Als je set- egebruikt, dan || :is een geweldige manier om niethet script af te sluiten als er een fout optreedt (het maakt het expliciet geslaagd).


Antwoord 4, autoriteit 3%

U zou :gebruiken om een ​​commando op te geven dat slaagt maar niets doet. In dit voorbeeld is de opdracht “breedsprakigheid” standaard uitgeschakeld door deze in te stellen op :. De ‘v’-optie zet het aan.

#!/bin/sh
# example
verbosity=:                         
while getopts v OPT ; do          
   case $OPT in                  
       v)        
           verbosity=/bin/realpath 
       ;;
       *)
           exit "Cancelled"
       ;;             
   esac                          
done                              
# `$verbosity` always succeeds by default, but does nothing.                              
for i in * ; do                   
  echo $i $($verbosity $i)         
done                              
$ example
   file
$ example -v
   file /home/me/file  

Antwoord 5, autoriteit 3%

Negeer aliasargumenten

Soms wil je een alias hebben die geen enkel argument nodig heeft. Je kunt het doen met ::

> alias alert_with_args='echo hello there'
> alias alert='echo hello there;:'
> alert_with_args blabla
hello there blabla
> alert blabla
hello there

Antwoord 6, autoriteit 3%

Eén gebruik is als commentaar met meerdere regels, of om een ​​deel van uw code te becommentariëren voor testdoeleinden door het te gebruiken in combinatie met een here-bestand.

: << 'EOF'
This part of the script is a commented out
EOF

Vergeet niet om aanhalingstekens rond EOFte gebruiken, zodat eventuele code erin niet wordt geëvalueerd, zoals $(foo). Het kan ook de moeite waard zijn om een ​​intuïtieve terminatornaam te gebruiken, zoals NOTES, SCRATCHPADof TODO.


Antwoord 7

Twee van mij.

POD-opmerkingen insluiten

Een behoorlijk funky toepassing van :is voor het insluiten van POD-commentaar in bash-scripts, zodat man-pagina’s snel kunnen worden gegenereerd. Natuurlijk zou je uiteindelijk het hele script in Perl herschrijven 😉

Runtime functie binding

Dit is een soort codepatroon voor bindingsfuncties tijdens runtime.
F.i., heb een foutopsporingsfunctie om iets alleen te doen als een bepaalde vlag is ingesteld:

#!/bin/bash
# noop-demo.sh 
shopt -s expand_aliases
dbg=${DBG:-''}
function _log_dbg {
    echo >&2 "[DBG] $@"
}
log_dbg_hook=':'
[ "$dbg" ] && log_dbg_hook='_log_dbg'
alias log_dbg=$log_dbg_hook
echo "Testing noop alias..."
log_dbg 'foo' 'bar'

Je krijgt:

$ ./noop-demo.sh 
Testing noop alias...
$ DBG=1 ./noop-demo.sh 
Testing noop alias...
[DBG] foo bar

Antwoord 8

Enigszins gerelateerd aan dit antwoord, vind ik deze no-op nogal handig om polyglotscripts. Hier is bijvoorbeeld een geldige opmerking voor zowel bash als vimscript:

":" #    this is a comment
":" #    in bash, ‘:’ is a no-op and ‘#’ starts a comment line
":" #    in vimscript, ‘"’ starts a comment line

Natuurlijk hebben we truenet zo goed gebruikt, maar dat :een interpunctieteken is en geen irrelevant Engels woord, maakt duidelijk dat het een syntaxisteken is.


Wat betreft waaromzou iemand zoiets lastigs doen als het schrijven van een polyglot-script (behalve dat het cool is): het is handig in situaties waarin we normaal gesproken meerdere scriptbestanden in verschillende talen zouden schrijven, met bestand Xverwijzend naar bestand Y.

In een dergelijke situatie vermijdt het combineren van beide scripts in een enkel, polyglot-bestand elk werk in Xvoor het bepalen van het pad naar Y(het is gewoon "$0"). Wat nog belangrijker is, het maakt het gemakkelijker om het programma te verplaatsen of te verspreiden.

  • Een veelvoorkomend voorbeeld.Er is een bekend, al lang bestaand probleem met shebangs: de meeste systemen (inclusief Linux en Cygwin) staan ​​slechts éénargument toe doorgeven aan de tolk. De volgende klootzak:

    #!/usr/bin/env interpreter --load-libA --load-libB
    

    zal het volgende commando uitvoeren:

    /usr/bin/env "interpreter --load-libA --load-libB" "/path/to/script"
    

    en niet de beoogde:

    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    Dus je zou uiteindelijk een wrapper-script schrijven, zoals:

    #!/usr/bin/env sh
    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    Dit is waar polyglossia het podium betreedt.

  • Een specifieker voorbeeld.Ik heb ooit een bash-script geschreven dat onder andere Vim aanriep. Ik moest Vim extra instellingen geven, wat gedaan kon worden met de optie --cmd "arbitrary vimscript command here". Die opzet was echter aanzienlijk, dus het zou verschrikkelijk zijn geweest om het in een string te plaatsen (indien ooit mogelijk). Daarom was een betere oplossing om het in extensoin een configuratiebestand te schrijven en Vim dat bestand vervolgens te laten lezen met -S "/path/to/file". Vandaar dat ik eindigde met een polyglot bash/vimscript-bestand.


Antwoord 9

stel dat je een commando hebt dat je wilt koppelen aan het succes van een ander:

cmd="some command..."
$cmd
[ $? -eq 0 ] && some-other-command

maar nu wil je de commando’s voorwaardelijk uitvoeren en wil je de commando’s laten zien die zouden worden uitgevoerd (dry-run):

cmd="some command..."
[ ! -z "$DEBUG" ] && echo $cmd
[ -z "$NOEXEC" ] && $cmd
[ $? -eq 0 ] && {
    cmd="some-other-command"
    [ ! -z "$DEBUG" ] && echo $cmd
    [ -z "$NOEXEC" ] && $cmd
}

dus als je DEBUG en NOEXEC instelt, verschijnt het tweede commando nooit. dit komt omdat het eerste commando nooit wordt uitgevoerd (omdat NOEXEC niet leeg is), maar de evaluatie van dat feit geeft je een resultaat van 1, wat betekent dat het ondergeschikte commando nooit wordt uitgevoerd (maar je wilt het wel omdat het een droge run is). dus om dit op te lossen kun je de exit-waarde die nog op de stapel staat resetten met een noop:

[ -z "$NOEXEC" ] && $cmd || :

Antwoord 10

Soms kunnen no-op-clausules uw code leesbaarder maken.

Dat kan een kwestie van mening zijn, maar hier is een voorbeeld. Laten we aannemen dat je een functie hebt gemaakt die werkt door twee Unix-paden te nemen. Het berekent het ‘veranderingspad’ dat nodig is om van het ene pad naar het andere te gaan. U plaatst een beperking op uw functie dat de paden beide moeten beginnen met een ‘/’ OF beide niet.

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        true      # continue with function
    else
        return 1  # Skip function.
    fi

Sommige ontwikkelaars zullen de no-op willen verwijderen, maar dat zou betekenen dat de voorwaardelijke teniet wordt gedaan:

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" != / || "$fromC" == / ]] && [[ "$toC" == / || "$fromC" != / ]]
    then
        return 1  # Skip function.
    fi

Nu is -naar mijn mening- niet zo duidelijk uit de if-clause onder welke voorwaarden je de functie zou willen overslaan. Om de no-op te elimineren en het duidelijk te doen, zou je de if-clausule uit de functie willen verwijderen:

   if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        cdPath=$(chgPath pathA pathB)   # (we moved the conditional outside)

Dat ziet er beter uit, maar vaak kunnen we dit niet; we willen dat de controle binnen de functie wordt uitgevoerd.

Dus hoe vaak gebeurt dit? Niet zo vaak. Misschien een of twee keer per jaar. Het komt vaak genoeg voor, dat je je ervan bewust moet zijn. Ik schuw het niet om het te gebruiken als ik denk dat het de leesbaarheid van mijn code verbetert (ongeacht de taal).


Antwoord 11

Ik heb er ook scripts in gebruikt om standaardvariabelen te definiëren.


: ${VARIABLE1:=my_default_value}
: ${VARIABLE2:=other_default_value}
call-my-script ${VARIABLE1} ${VARIABLE2}

Antwoord 12

Ik gebruik het soms op Docker-bestanden om RUN-commando’s uitgelijnd te houden, zoals in:

RUN : \
    && somecommand1 \
    && somecommand2 \
    && somecommand3

Voor mij leest het beter dan:

RUN somecommand1 \
    && somecommand2 \
    && somecommand3

Maar dit is natuurlijk slechts een kwestie van voorkeur

Other episodes