Nybörjarens guide till Shell Scripting 2 för loopar
Om du vill bygga upp din nördkredit, kom med oss för den andra delen i vår skalskriptserie. Vi har några korrigeringar, några förbättringar till förra veckans manus och en guide för looping för de oinitierade.
Datecp Script Revisited
I den första delen av vår skalskriptguide gav vi ett skript som kopierade en fil till en säkerhetskatalog efter att ha bifogat datumet till slutet av filnamnet.
Samuel Dionne-Riel påpekade i kommentarerna att det finns ett mycket bättre sätt att hantera våra variabla referenser.
Argument är rymdeseparerade i bash-skalet, det kommer att tokenize när det finns ett mellanslag i det resulterade expanderade kommandot. I ditt skript,
cp $ 1 $ 2. $ date_formatted
kommer att fungera som avsedd så länge som de expanderade variablerna inte har mellanslag i dem. Om du ringer ditt skript så här:datecp "mitt gamla namn" "mitt nya namn"
Expansionen kommer att resultera i detta kommando:cp mitt nya namn mitt gamla namn.the_date
som faktiskt har 6 argument.För att lösa problemet korrekt måste den sista raden i skriptet vara:
cp "$ 1" "$ 2. $ date_formatted"
Som du kan se ändrar du vårt skript linje från:
cp -iv $ 1 $ 2. $ date_formatted
till:
cp -iv "$ 1" "$ 2". $ date_formatted
kommer att ta hand om detta problem när du använder skriptet på filer som har mellanslag i namnet. Samuel gör också att när du kopierar och klistrar kod från den här webbplatsen (eller internet i allmänhet), måste du ersätta rätt streck och citat för de "typografiskt bättre" de som ofta ersätter dem. Vi gör också mer för att se till att vår kod är mer kopiera / klistra in. ;-)
En annan commenter, Myles Braithwaite, bestämde sig för att utöka vårt skript så att datumet skulle visas före filtillägget. Så istället för
tastyfile.mp3.07_14_11-12.34.56
vi skulle få det här:
tastyfile.07_14_11-12.34.56.mp3
vilket slutar vara lite bekvämare för de flesta användare. Hans kod finns på hans GitHub-sida. Låt oss ta en titt på vad han använder för att dra ihop filnamnet.
date_formatted = $ (datum +% Y-% m-% d_% H.% M% S)
file_extension = $ (echo "$ 1" | awk -F. 'skriv ut $ NF')
file_name = $ (basnamn $ 1. $ file_extension)cp -iv $ 1 $ file_name- $ date_formatted. $ file_extension
Jag har ändrat formateringen lite, men du kan se att Myles förklarar sin datumfunktion i rad 1. I linje 2 använder han emellertid "echo" -kommandot med det första argumentet för manuset för att utmata filens namn. Han använder pipkommandot för att ta den produktionen och använda den som ingång för nästa del. Efter röret kallar Myles kommandot "awk", vilket är ett kraftfullt mönsterskanningsprogram. Med hjälp av -F-flaggan, säger han kommandot att nästa tecken (efter ett mellanslag) är vad som kommer att definiera "fältavskiljaren". I det här fallet är det en period.
Nu, awk se en fil med namnet "tastyfile.mp3" som består av två fält: "tastyfile" och "mp3". Till sist använder han
'skriv ut $ NF'
för att visa det sista fältet. Om din fil har flera perioder - så gör awk, se flera fält - det visar bara den sista, som är filtillägget.
I rad 3 skapar han en ny variabel för filens namn och använder kommandot "basename" för att referera till allt i $ 1 bortsett från filtillägget. Detta görs genom att använda basnamn och ge det $ 1 som sitt argument, sedan lägga till ett mellanslag och filtillägget. Filförlängningen läggs automatiskt in på grund av variabeln som hänvisar till Linje 2. Vad detta skulle göra är att ta
tastyfile.mp3
och vrid den in i
tastyfile
Sedan lägger Myles i den sista raden kommandot som kommer att mata ut allt i ordning. Observera att det inte finns någon hänvisning till $ 2, ett andra argument för manuset. Detta specifika skript kommer istället att kopiera filen till din nuvarande katalog. Stort jobb Samuel och Myles!
Löpande skript och $ PATH
Vi nämner också i vår Grundläggande artikel att skript inte får refereras till som kommandon som standard. Det betyder att du måste peka på sökvägen för manuset för att köra det:
./manus
~ / Bin / script
Men genom att placera dina skript i ~ / bin /, kan du bara skriva in deras namn var som helst för att få dem att springa.
Kommentarare spenderade tid på att diskutera hur korrekt detta var, eftersom ingen modern Linux distro skapar den katalogen som standard. Dessutom lägger ingen heller den till $ PATH-variabeln som standard, vilket är vad som krävs för att skript ska kunna köras som kommandon. Jag var lite förbryllad för att efter att ha kontrollerat min $ PATH-variabel var kommentaren rätt, men anropskript fungerade fortfarande för mig. Jag fick reda på varför: många moderna Linux distros skapar en speciell fil i användarens hemkatalog - .profile.
Den här filen läses av bash (om inte .bash_profile finns i användarens hemkatalog) och längst ner finns en sektion som lägger till ~ / bin / mappen till variabeln $ PATH om den existerar. Så, det här mysteriet är klarat. För resten av serien fortsätter jag med att lägga skript i ~ / bin / katalog eftersom de är användarskript och ska kunna köras av användare. Och det verkar som om vi verkligen inte behöver röra med $ PATH-variabeln för hand för att få saker att fungera.
Upprepa kommandon med loopar
Låt oss komma till ett av de mest användbara verktygen i geekarsenalen för att hantera repetitiva uppgifter: loopar. Idag diskuterar vi "för" loopar.
Grunderna för en för-loop är som följer:
för VARIABLE i LIST; do
kommando1
kommando2
...
commandn
Gjort
VARIABLE kan vara vilken variabel som helst, men oftast används den små bokstaven "i" enligt konventionen. LIST är en lista över objekt; Du kan ange flera objekt (separera dem med ett mellanslag), peka på en extern textfil eller använd en asterisk (*) för att ange vilken fil som helst i den aktuella katalogen. De angivna kommandona är indragna enligt konventionen, så det är lättare att se nesting - slingar slingor i slingor (så att du kan slinga medan du slingrar).
Eftersom listor använder mellanslag som avgränsare - det vill säga ett mellanslag betyder ett steg till nästa objekt i listan - filer som har mellanslag i namnet är inte särskilt vänliga. För tillfället, låt oss hålla fast vid att arbeta med filer utan mellanslag. Börja med ett enkelt skript för att visa namnen på filer i den aktuella katalogen. Skapa ett nytt skript i din ~ / bin / folder med titeln "loopscript". Om du inte kommer ihåg hur man gör det här (inklusive att markera det som körbart och lägga till hashbarkhack) hänvisar du till vår bash scripting-basics artikel.
I det anger du följande kod:
för jag i item1 item2 item3 item4 item5 item6; do
eko "$ i"
Gjort
När du kör skriptet ska du bara få de listannonserna som utgång.
Ganska enkelt, eller hur? Låt oss se vad som händer om vi ändrar saker upp lite. Ändra ditt skript så det står här:
för jag i *; do
eko "$ i"
Gjort
När du kör det här skriptet i en mapp ska du få en lista över filer som den innehåller som utgång.
Nu, låt oss ändra ekkokommandot till något mer användbart - säg zip-kommandot. Namnlösa: Vi lägger till filer i ett arkiv. Och låt oss få några argument i blandningen!
för jag i $ @; do
zip arkiv "$ i"
Gjort
Det finns något nytt! "$ @" Är en genväg för "$ 1 $ 2 $ 3 ... $ n". Det är med andra ord den fullständiga listan över alla argument du angav. Nu, se vad som händer när jag kör skriptet med flera inmatningsfiler.
Du kan se vilka filer som finns i min mapp. Jag sprang kommandot med sex argument, och varje fil lagdes till ett zippat arkiv med namnet "archive.zip". Lätt, rätt?
För loopar är ganska underbara. Nu kan du utföra batchfunktioner på listor över filer. Du kan till exempel kopiera alla skriptets argument till ett zip-arkiv, flytta originalen till en annan mapp och säkra automatiskt kopiera den zip-filen till en fjärrdator. Om du ställer in nyckelfiler med SSH behöver du inte ens ange ditt lösenord, och du kan till och med säga att skriptet tar bort zip-filen efter uppladdning!
Att använda för-loopar gör det enkelt att göra en massa åtgärder för alla filer i en katalog. Du kan stapla ett brett utbud av kommandon tillsammans och använda argument mycket enkelt för att skapa och flyga listan, och detta är bara toppen av isberget.
Bash scripters, har du några förslag? Har du gjort ett användbart skript som använder slingor? Vill du dela med dig av dina tankar på serien? Lämna några kommentarer och hjälp andra scripting newbies ut!