Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.
Hjälp med bash-script
Använd `pgrep` från paketet `procps` för att hitta processer. Typ:
#!/bin/sh
while sleep 30m; do
if pgrep boinc > /dev/null; then
boinccmd --get_state
fi
done
Vad använder du loggningen till? Den skrivs ju över varje gång i loopen. Jag tog bort den då jag inte riktigt ser vad den är till för, men det är möjligt att du har den för externa ändamål. Om du vill spara den, men samtidigt skriva ut resultatet till terminalen, så föreslår jag:
#!/bin/sh
while sleep 30m; do
if pgrep boinc > /dev/null; then
boinccmd --get_state | tee ~/.config/openbox/clientstate.txt
fi
done
Man skulle kunna trycka ihop allt till
#!/bin/sh
while sleep 30m; do
pgrep boinc > /dev/null && boinccmd --get_state | tee ~/.config/openbox/clientstate.txt
done
om man känner för det, men det ger ingen egentlig vinst — det enda som händer är att koden möjligen blir lite mindre lättläst. Om du dock vill lägga detta i `cron` i stället så att systemet ser till att köra detta en gång i halvtimmen så kan one-linern vara smidig.
Jag använder `#!/bin/sh` i stället för `#!/bin/bash`. Om man inte behöver några Bashspecifika konstruktioner så finns det ingen anledning att kalla just Bash.
—
Lite kommentarer på din kod:
COUNTER = "0"
Detta kommer inte fungera. Du kan inte ha mellanrum bredvid likhetstecknet under tilldelning här. Detta kommer säga `bash: COUNTER: command not found` då Bash tror att du vill köra programmet som heter `COUNTER` med argumenten `=` och `0`.
if [ top -b | grep 'boinc' == 'boinc' ]; then
Detta kommer inte fungera. Du kan inte ha ett funktionsanrop på det sättet i ett test. Du behöver öppna ett "subskal" och fånga output. Detta gör man företrädelsevis via t ex:
if [ "$(top -b | grep boinc)" = "boinc" ]; then
Notera att jag ändrade "==" till "=". Det må se bakvänt ut, men ett enstaka "=" är faktiskt hur man jämför strängar i shell script. "==" är ett Bashtillägg, för att blidka de som är vana vid andra språk skulle jag tro, men det är egentligen onödigt här. Det kan finnas anledningar att använda Bashs egna testkonstruktioner utöver de som är definierade i POSIX (för "standardskalet"), men det är rätt sällan. Till att börja med bör man då använda Bashs syntax med dubbla klamrar: `[[ 'a' == 'b' ]]`, för att tydliggöra att man använder en Bashspecifik funktion.
Dessutom, vilket jag kommer referera till nedan, så har standardkonstruktionen med enkla hakparanteser en speciell jämförelseoperator att använda till heltalsjämförelser: utöver `-lt` för "less than", `le` för "less or equal than", `-ge` för "greater or equal than` och `-gt` för "greater than" så finns `-eq` för "equals". Så `[ 5 -eq 5 ]` är sant, `[ 5 -eq 6 ]` är falskt, och `[ 5 -eq "katt" ]` klagar på att "katt" inte är ett heltal.
Ett annat problem är att `top -b` inte kommer returnera endast strängen "boinc", så det testet kommer aldrig bli sant. Undvik hemmasnickrade `grep`-lösningar för att hitta processer — använd `pgrep` i stället. Det är sjukt poppis att pipe:a output från `ps` till `awk` och annat, och visst fungerar det ofta, men man hamnar i problem som att man behöver exkludera själva sökkommandot på något sätt, kanske genom ett extra `grep -v`-kommando, och det ger ibland oväntade resultat. Output från `ps` är tänkt för presentation för användare, inte direkt att vara parsningsbar för program. Använd `pgrep`, eller specifika bibliotek ifall scriptandet sker i Perl (t ex Proc::ProcessTable) eller Python (t ex psutil).
Om du vill testa om ett `grep`-mönster träffar så är det mycket bättre att använda `grep`-växeln `-q`, som returnerar `true` (dvs "exit status 0") om mönstret träffar, och `false` ("exit status 1") om mönstret inte träffar, så att man kan skriva t ex:
if grep -q kossa stallförteckning.txt; then
echo "Det finns en ko i stallet!"
else
echo "Kofritt i stallet."
fi
Ovanstående visar också hur man använder just "exit status" för en process för att styra logikflödet.
COUNTER="1"
else
COUNTER="0"
Använd de inbyggda värdena "true" och "false" i stället, exempelvis:
if [ "$DJUR" = "katt" ]; then
KATT=true
else
KATT=false
fi
En lustig sak att nämna med shell script är att "0" på vissa sätt är närmre "true" än icke-0; specifikt i returkoder från processer. Det blir lätt lite bakvänt om man börjar använda "0" och "1" som pseudobooleaner, och som sagt så finns redan "true"/"false". Notera liten begynnelsebokstav!
Liten utläggning: `true` och `false` är faktiskt två vanliga program som ligger i `/bin`. `man false` ger den fantastiska förklaringen för vad `false` gör: "false - do nothing, unsuccessfully" . I praktiken så ersätts de dock av inbyggda funktioner i respektive skal, så t ex Bash har en egen `false`-funktion som tar företräde. Detta gör att Bash inte behöver skapa en ny process, vilket sparar datortid. Detta gäller även för t ex `echo`, `test` och en del andra funktioner. Detta kan vara bra att veta om man hamnar framför en terminal där man bara har ett skal och alla program är borta — man kan komma hyfsat långt utan `ls`, `grep`, en texteditor, etc., om man är lite finurlig med skalets inbyggda funktioner .
while [ $COUNTER == 1 ]; do
`==` bör ändras till `=`, eller ännu hellre `-eq` enligt resonemanget ovan.
Om nu `$COUNTER` vore satt direkt till `true` eller `false` så hade ovanstående enklare kunnat skrivas:
while $COUNTER; do
Jag skrev i stället
while sleep 30m; do
som en sorts "genväg" till att göra en periodiskt upprepande funktion. När `sleep` är klart så returnerar programmet `true` (egentligen returstatus `0`, vilket tolkas som sant — icke-0 vore falskt) och loopen körs.
cd /usr/bin
boinccmd --get_state > ~/.config/openbox/clientstate.txt
`/usr/bin` är säkerligen med i din `$PATH`. Om du bara skriver t ex `grep` i en terminal så letar skalet efter en körbar fil som heter just `grep` i de sökvägar som är angivna i `$PATH` automatiskt. Om du skriver `which grep` så ser du att den `grep`-variant som körs automatiskt troligen ligger i `/bin/grep` — men det är ju onödigt att `cd`:a dit innan programmet körs.
På samma sätt så kan du med gott samvete helt enkelt skippa `cd /usr/bin` här.
cd ~/.config/openbox/
cat clientstate.txt
Samma sak här, på sätt och vis. Skriv bara `cat ~/.config/openbox/clientstate.txt` direkt i stället. Enklare än att behöva hoppa runt i katalogträdet.
sleep 30m
Detta är möjligen ett logikfel. Vi kommer bara hit ifall `$COUNTER` var sann — så ifall `boinc` inte kördes så kommer ditt skript inte ens vara inne i denna loop och därmed avslutas direkt. Det är möjligt att det är vad du vill, men det känns naturligare att vilja att kontrollskriptet kör hela tiden och automatiskt går igång om den "känner" att `boinc` körs.
På samma sätt är din `while [ $COUNTER == 1 ]` lite konstig: ifall den är sann första gången, så är den alltid sann, eftersom `$COUNTER` inte ändras i loopen. Mer logiskt att följa vore typ:
if [ $COUNTER -eq 1 ]; then
while true; do
eller än hellre tricket med `sleep`, eller än hellre genom att bara stoppa in denna logik i den `if`-sats där du sätter `$COUNTER` till att börja med. Det blir bara mer kod och mindre överblickbart att ha separata konstruktioner här.
Hej phz!
Tusen tack för hjälpen! Jag har det mycket riktigt för externa ändamål, även om det inte blir något vettigt av det troligtvis.
Detta kommer inte fungera. Du kan inte ha mellanrum bredvid likhetstecknet under tilldelning här. Detta kommer säga `bash: COUNTER: command not found` för att Bash tror att du vill köra programmet som heter `COUNTER` med argumenten `=` och `0`.
Nu blev jag lite klokare
Detta kommer inte fungera. Du kan inte ha ett funktionsanrop på det sättet i ett test. Du behöver öppna ett "subskal" och fånga output. Detta gör man företrädelsevis via t ex:
Det hade jag ingen aning om. Inte konstigt att jag inte fick det att köras.
"while sleep 30m; do"
Aha...det känns som en bättre lösning att göra så
På samma sätt så kan du med gott samvete helt enkelt skippa `cd /usr/bin` här.
Anledningen till att jag har med det är att jag märkt att boinccmd ibland inte får någon authorization ifall kommandot körs ifrån fel mapp. Den hittar inte datan då, men ska kolla upp det här med $PATH och se om jag kan fixa något.
Detta är möjligen ett logikfel. Vi kommer bara hit ifall `$COUNTER` var sann — så ifall `boinc` inte kördes så kommer ditt skript inte ens vara inne i denna loop och därmed avslutas direkt.
Det har du helt rätt i. Ett logikfel från min sida. Meningen var att den skulle köras oavsett.
Jag har fått lära mig en hel del idag! Är där förresten någon särskild guide du kan rekommendera om jag vill lära mig mer om att göra *nix-script? Tack för att du tog dig tid att svara på ett så utförligt sätt på min fråga!
Jag har fått lära mig en hel del idag! Är där förresten någon särskild guide du kan rekommendera om jag vill lära mig mer om att göra *nix-script? Tack för att du tog dig tid att svara på ett så utförligt sätt på min fråga!
Det bästa sättet att lära sig är att skriva skript, gärna till någon faktisk uppgift man vill utföra (precis som du gjorde ovan), och att hela tiden gå tillbaka till äldre saker man skrivit och applicera det man lärt sig sedan sist. Mängdträning är det som ger "intuition" för vad som är den mest logiska angreppsvinkeln i varje situation.
Man ska också våga använda enkla konstruktioner direkt i skalet om man vill göra något repetitivt. Vill du packa upp 10 RAR-arkiv från olika kataloger? `for i in baskatalog/*/*.rar; do unrar e "$i"; done`. Sitter du i en datorsal och vill bli meddelad när din utskrift är klar? `while sleep 30; do if ! lpq | grep -q phz; then mplayer ohyeah.mp3; break; fi; done` — det var lite längre att skriva och blev lite oöverskådligt, och/eller så vill man göra det ofta — då sparar man det i en skriptfil. Små repetitiva uppgifter kan man lika gärna lämna över till datorn att utföra. Många ryggar inför att det kan ta lite tid att skriva koden innan man är van — men när den väl är skriven så kan man koncentrera sig mycket bättre på annat, och man eliminerar ofta "mänskliga faktorn", så det finns många vinster. Med tiden så blir man ju också snabbare på att skriva dessa skript, så man kan se det som en långsiktig tidsinvestering .
När man skriver så brukar det vara mycket "punktlärande", där man fastnar på någon liten sak, googlar på lösning och applicerar. Ett problem är att många kodexempel är skrivna rätt slarvigt, och ibland väldigt ineffektivt och oklart.
Greg's wiki hittar man rätt ofta när man söker i början, och det är en bra resurs. Där finns även en Bashguide om man gillar det upplägget. Vi kan notera att i listan över vanliga nybörjarmisstag så hade jag anledning att nämna i alla fall punkterna 9, 16, 19, 20 och 31 ovan .
Själv har jag lärt mig genom att dels skripta själv under många år, men även att läsa och svara på mycket frågor på Super User (och i mindre utsträckning här på SweClockers — här dyker det inte upp sådana frågor så ofta, dock ).
Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.
- Dator för videoredigering och grafiskt arbete - fungerar den här?7
- Battlefield 20423,8k
- Stop Killing Games har snart nått 1 miljon röster.48
- Tråden om Nintendo Switch 23,5k
- Vilka datorprylar vägrar du göra dig av med?16
- Nintendo Switch Online Family Membership diskussioner/dela membership med andra.203
- Vilket tangentbord ska jag köpa? Läs första inlägget först1,6k
- Guide: Mekaniska tangentbord2,4k
- Testpilot: MSI Raider A18 HX A9W – RTX 5080 och X3D-processor1
- Brain Drain Retro LAN 202527
- Säljes Galaxy tab s9 Ultra 5G 256Gb
- Säljes Retro: Intressekoll: Komponenter för Windows 95/98/NT/ME - cpu, moderkort, med mera
- Säljes LG 2021 65" OLED65C15LA
- Säljes Brother DCP-L2530DW Laser MFP
- Säljes Wood's Venezia 18K AC/Portabel Luftkondionering
- Säljes Intressekoll ok dator
- Säljes Nintendo Switch Oled
- Säljes HD Fury Arcana V1
- Köpes ASUS ROG STRIX HELIOS
- Säljes Nintendo Switch
- Testpilot: MSI Raider A18 HX A9W – RTX 5080 och X3D-processor1
- Stop Killing Games når 1 miljon påskrifter31
- HP vill göra det tryggare att köpa begagnad dator21
- KO stämmer Hallon för brister i kundtjänst35
- Quiz: Vad kan du om gränssnitt i spel?131
- PS5 Pro får förbättrad uppskalning under 202613
- Lordes nya CD så genomskinlig att kunder inte kan spela den33
- RTX 5060 Ti 16 GB 16 gånger populärare än 8 GB20
- Commodore köps av Youtuber44
- Nu har Microsoft allt tabbat sig: Förstör Alt+Tab i ny uppdatering24
Externa nyheter
Spelnyheter från FZ