webentwicklung-frage-antwort-db.com.de

Wie schreibt man ein Skript, das Eingaben aus einer Datei oder von stdin akzeptiert?

Wie kann man ein Skript schreiben, das Eingaben von einem Dateinamenargument oder von stdin akzeptiert?

zum Beispiel könnten Sie auf diese Weise less verwenden. man kann less filename und gleichwertig cat filename | less ausführen.

gibt es einen einfachen "out of the box" Weg, dies zu tun? Oder muss ich das Rad neu erfinden und ein bisschen Logik in das Skript schreiben?

53
gilad hoch

Wenn das Dateiargument das erste Argument für Ihr Skript ist, prüfen Sie, ob es ein Argument ($1) und eine Datei gibt. Sonst lese die Eingabe von stdin -

Ihr Skript könnte also etwa Folgendes enthalten:

#!/bin/bash
[ $# -ge 1 -a -f "$1" ] && input="$1" || input="-"
cat $input

z.B. dann kannst du das script gerne aufrufen

./myscript.sh filename

oder

who | ./myscript.sh

Bearbeiten Eine Erklärung des Skripts:

[ $# -ge 1 -a -f "$1" ] - Wenn mindestens ein Befehlszeilenargument ($# -ge 1) UND (-a Operator) das erste Argument eine Datei ist (-f testet, ob "$ 1" eine Datei ist), ist das Testergebnis wahr.

&& ist der logische AND-Operator der Shell. Wenn der Test wahr ist, geben input="$1" und cat $input die Datei aus.

|| ist der logische OR -Operator der Shell. Wenn der Test falsch ist, werden Befehle nach || analysiert. Eingang ist mit "-" belegt. cat - liest von der Tastatur.

Zusammenfassend wird, wenn das Skriptargument bereitgestellt wird und es sich um eine Datei handelt, die Variableneingabe dem Dateinamen zugewiesen. Wenn es kein gültiges Argument gibt, liest cat von der Tastatur.

57
suspectus

read liest von der Standardeingabe. Das Umleiten von der Datei (./script <someinput) oder über die Pipe (dosomething | ./script) führt nicht zu einer anderen Funktionsweise.

Alles, was Sie tun müssen, ist, alle Zeilen in der Eingabe zu durchlaufen (und es unterscheidet sich nicht von der Iteration über die Zeilen in der Datei).

(Beispielcode, verarbeitet nur eine Zeile)

#!/bin/bash

read var
echo $var

Gibt die erste Zeile Ihrer Standardeingabe aus (entweder durch < oder |).

12
Lukasz Daniluk

Der einfachste Weg ist, stdin selbst umzuleiten:

if [ "$1" ] ; then exec < "$1" ; fi

Oder wenn Sie die knappere Form bevorzugen:

test "$1" && exec < "$1"

Jetzt kann der Rest Ihres Skripts nur noch von stdin lesen. Natürlich können Sie die Position des Dateinamens auch mit erweiterten Optionen analysieren, anstatt ihn fest als "$1" zu codieren.

4
R..

Sie erwähnen nicht, welche Shell Sie verwenden möchten, also nehme ich Bash an, obwohl dies bei allen Shells ziemlich übliche Dinge sind.

Datei Argumente

Auf Argumente kann über die Variablen $1-$n zugegriffen werden ($0 gibt den Befehl zurück, der zum Ausführen des Programms verwendet wird). Angenommen, ich habe ein Skript, das nur catn Anzahl von Dateien mit einem Trennzeichen dazwischen ausgibt:

#!/usr/bin/env bash
#
# Parameters:
#    1:   string delimiter between arguments 2-n
#    2-n: file(s) to cat out
for arg in ${@:2} # [email protected] is the array of arguments, ${@:2} slices it starting at 2.
do
   cat $arg
   echo $1
done

In diesem Fall übergeben wir einen Dateinamen an cat. Wenn Sie jedoch die Daten in der Datei transformieren möchten (ohne sie explizit zu schreiben und neu zu schreiben), können Sie den Dateiinhalt auch in einer Variablen speichern:

file_contents=$(cat $filename)
[...do some stuff...]
echo $file_contents >> $new_filename

Lesen Sie von stdin

Was das Lesen von stdin angeht, haben die meisten Shells eine ziemlich standardmäßige read eingebaut, obwohl es (zumindest) Unterschiede in der Art und Weise gibt, wie Eingabeaufforderungen angegeben werden.

Die Bash builtins man page hat eine ziemlich kurze Erklärung von read, aber ich bevorzuge die Bash Hackers page.

Einfach:

read var_name

Mehrere Variablen

Geben Sie zum Festlegen mehrerer Variablen einfach mehrere Parameternamen für read an:

read var1 var2 var3

read fügt dann ein Wort aus stdin in jede Variable ein und fügt alle verbleibenden Wörter in die letzte Variable ein.

λ read var1 var2 var3
thing1 thing2 thing3 thing4 thing5
λ echo $var1; echo $var2; echo $var3
thing1
thing2
thing3 thing4 thing5

Wenn weniger Wörter als Variablen eingegeben werden, sind die verbleibenden Variablen leer (auch wenn sie zuvor festgelegt wurden):

λ read var1 var2 var3
thing1 thing2
λ echo $var1; echo $var2; echo $var3
thing1
thing2
# Empty line

Eingabeaufforderungen

Ich benutze das -p Flag oft für eine Eingabeaufforderung:

read -p "Enter filename: " filename

Hinweis: ZSH und KSH (und möglicherweise auch andere) verwenden für Eingabeaufforderungen eine andere Syntax:

read "filename?Enter filename: " # Everything following the '?' is the Prompt

Standardwerte

Dies ist eigentlich kein read-Trick, aber ich verwende ihn häufig in Verbindung mit read. Zum Beispiel:

read -p "Y/[N]: " reply
reply=${reply:-N}

Wenn die Variable (reply) vorhanden ist, geben Sie sich selbst zurück. Wenn sie leer ist, geben Sie den folgenden Parameter zurück ("N").

4
Jacob Hayes

benutze (oder verkette) etwas anderes, das sich bereits so verhält, und benutze "[email protected]"

angenommen, ich möchte ein Tool schreiben, das Leerzeichen in Text durch Tabulatoren ersetzt

tr ist der naheliegendste Weg, dies zu tun, aber es nur akzeptiert stdin, also müssen wir cat verketten:

$ cat entab1.sh
#!/bin/sh

cat "[email protected]"|tr -s ' ' '\t'
$ cat entab1.sh|./entab1.sh
#!/bin/sh

cat     "[email protected]"|tr -s      '       '       '\t'
$ ./entab1.sh entab1.sh
#!/bin/sh

cat     "[email protected]"|tr -s      '       '       '\t'
$ 

für ein Beispiel, in dem sich das verwendete Tool bereits so verhält, könnten wir dies stattdessen mit sed neu implementieren:

$ cat entab2.sh
#!/bin/sh

sed -r 's/ +/\t/g' "[email protected]"
$ 
3
Aaron Davies

Sie können auch:

#!/usr/bin/env bash

# Set variable input_file to either $1 or /dev/stdin, in case $1 is empty
# Note that this assumes that you are expecting the file name to operate on on $1
input_file="${1:-/dev/stdin}"

# You can now use "$input_file" as your file to operate on
cat "$input_file"

Weitere nützliche Tricks zum Ersetzen von Parametern in Bash finden Sie unter this .

3
Daniel

Der einfachste Weg und POSIX-konform ist:

file=${1--}

das entspricht ${1:--}.

Dann lies die Datei wie gewohnt:

while IFS= read -r line; do
  printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
0
kenorb

Sie können es auch einfach halten und diesen Code verwenden


Wenn Sie eine Skriptdatei pass_it_on.sh mit diesem Code erstellen,

#!/bin/bash

cat

Du kannst rennen

cat SOMEFILE.txt | ./pass_it_on.sh

und der gesamte inhalt von stdin wird einfach auf den bildschirm gespritzt.


Alternativ können Sie diesen Code verwenden, um eine Kopie von stdin in einer Datei zu speichern und diese dann auf den Bildschirm auszugeben.

#!/bin/bash

tmpFile=`mktemp`
cat > $tmpFile
cat $tmpFile    

und hier ist ein weiteres Beispiel, vielleicht besser lesbar, das hier erklärt wird:

http://mockingeye.com/blog/2013/01/22/reading-everything-stdin-in-a-bash-script/

#!/bin/bash

VALUE=$(cat)

echo "$VALUE"

Habe Spaß.

RaamEE

0
RaamEE