Jak odczytać z pliku lub stdin w Bash?
W Perlu następujący kod będzie odczytywany z pliku określonego w args linii poleceń lub ze standardowego wejścia:
while (<>) {
print($_);
}
To bardzo wygodne. Chcę tylko wiedzieć, jaki jest najprostszy sposób odczytu z pliku lub stdin w bash. 14 answers
Poniższe rozwiązanie odczytuje z pliku, jeśli skrypt jest wywołany
z nazwą pliku jako pierwszym parametrem $1
, w przeciwnym razie ze standardowego wejścia.
while read line
do
echo "$line"
done < "${1:-/dev/stdin}"
Substytucja ${1:-...}
przyjmuje $1
jeśli zdefiniowano inaczej
używana jest nazwa pliku standardowego wejścia własnego procesu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-19 20:37:09
Być może najprostszym rozwiązaniem jest przekierowanie stdin za pomocą łączącego się operatora przekierowania:
#!/bin/bash
less <&0
Stdin jest deskryptorem pliku zero. Powyższe polecenie wysyła sygnał wejściowy do skryptu bash na stdin less.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 20:48:52
Oto najprostszy sposób:
#!/bin/sh
cat -
Użycie:
$ echo test | sh my_script.sh
test
Aby przypisać stdin do zmiennej, możesz użyć: STDIN=$(cat -)
lub po prostu {[5] } jako operator nie jest konieczny (zgodnie z @mklement0 komentarz).
Aby przetworzyć każdą linię ze standardowego wejścia , spróbuj użyć następującego skryptu:
#!/bin/bash
while IFS= read -r line; do
printf '%s\n' "$line"
done
Aby odczytać z pliku lub stdin (jeśli argument nie jest obecny), możesz rozszerzyć go do:
#!/bin/bash
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
Uwagi:
-
read -r
- nie traktuj znaku ukośnika w żaden szczególny sposób. Rozważ każdy ukośnik wsteczny jako część linii wejściowej.- BEZ Ustawienia
IFS
, domyślnie sekwencje spacji i tabulacji na początku i końcu linii są ignorowane (przycięte).- użyj
printf
zamiastecho
, aby uniknąć drukowania pustych linii, gdy linia składa się z jednego-e
,-n
lub-E
. Jednak tam jest obejściem za pomocąenv POSIXLY_CORRECT=1 echo "$line"
, który wykonuje twój zewnętrzny GNUecho
, który go obsługuje. Zobacz: jak echo "- e"?
Zobacz: jak odczytać stdin, gdy nie są przekazywane żadne argumenty? w stackoverflow SE
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:48
Rozwiązanie echo
dodaje nowe linie za każdym razem, gdy IFS
przerywa strumień wejściowy. odpowiedź@fgm można nieco zmodyfikować:
cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:48
Myślę, że to jest prosta droga:
$ cat reader.sh
#!/bin/bash
while read line; do
echo "reading: ${line}"
done < /dev/stdin
--
$ cat writer.sh
#!/bin/bash
for i in {0..5}; do
echo "line ${i}"
done
--
$ ./writer.sh | ./reader.sh
reading: line 0
reading: line 1
reading: line 2
reading: line 3
reading: line 4
reading: line 5
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 19:25:26
Pętla Perla w pytaniu odczytuje z wszystkie argumenty nazwy pliku z linii poleceń, lub ze standardowego wejścia, jeśli nie podano żadnych plików. Odpowiedzi, które widzę, wydają się przetwarzać pojedynczy plik lub standardowe wejście, jeśli nie podano PLIKU.
Chociaż często wyśmiewane dokładnie jako UUOC (bezużyteczne użycie cat
), są chwile, kiedy cat
jest najlepszym narzędziem do pracy, i można się domyślić, że jest to jedno z nich: {10]}
cat "$@" |
while read -r line
do
echo "$line"
done
Jedynym minusem tego jest tworzy rurociąg działający w pod-powłoce, więc rzeczy takie jak przypisanie zmiennych w pętli while
nie są dostępne poza rurociągiem. bash
wokół tego jest substytucja procesu :
while read -r line
do
echo "$line"
done < <(cat "$@")
To powoduje, że pętla while
działa w głównej powłoce, więc zmienne ustawione w pętli są dostępne poza pętlą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-27 16:18:34
Zachowanie Perla, z kodem podanym w OP może przyjmować żaden lub kilka argumentów, a jeśli argument jest pojedynczym myślnikiem -
jest to rozumiane jako stdin. Co więcej, zawsze można mieć nazwę pliku z $ARGV
.
Żadna z udzielonych dotąd odpowiedzi nie naśladuje zachowania Perla pod tym względem. Tutaj jest możliwość czystej Bash. Sztuczka polega na odpowiednim użyciu exec
.
#!/bin/bash
(($#)) || set -- -
while (($#)); do
{ [[ $1 = - ]] || exec < "$1"; } &&
while read -r; do
printf '%s\n' "$REPLY"
done
shift
done
Nazwa pliku jest dostępna w $1
.
Jeśli nie podano argumentów, sztucznie ustawiamy -
jako pierwszy parametr pozycyjny. Następnie zapętlamy parametry. Jeśli parametr nie jest -
, przekierowujemy standardowe wejście z nazwy pliku za pomocą exec
. Jeśli to przekierowanie się powiedzie, pętlę wykonujemy pętlą while
. Używam standardowej zmiennej REPLY
i w tym przypadku nie trzeba resetować IFS
. Jeśli chcesz inną nazwę, musisz zresetować IFS
w ten sposób (chyba, że oczywiście nie chcesz tego i wiesz, co robisz): {]}
while IFS= read -r line; do
printf '%s\n' "$line"
done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-28 23:19:42
Dokładniej...
while IFS= read -r line ; do
printf "%s\n" "$line"
done < file
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-08 12:51:51
Proszę wypróbować następujący kod:
while IFS= read -r line; do
echo "$line"
done < file
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-28 23:42:24
Kod ${1:-/dev/stdin}
zrozumie tylko pierwszy argument, więc co ty na to?
ARGS='$*'
if [ -z "$*" ]; then
ARGS='-'
fi
eval "cat -- $ARGS" | while read line
do
echo "$line"
done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-08 15:10:37
Poniższe działa ze standardem sh
(testowanym z dash
na Debianie) i jest dość czytelne, ale to kwestia gustu:
if [ -n "$1" ]; then
cat "$1"
else
cat
fi | commands_and_transformations
Szczegóły: jeśli pierwszy parametr jest niepusty, to cat
ten plik, else cat
standardowe wejście. Następnie wyjście całej instrukcji if
jest przetwarzane przez commands_and_transformations
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-30 14:47:26
Nie uważam żadnej z tych odpowiedzi za akceptowalną. W szczególności, zaakceptowana odpowiedź obsługuje tylko pierwszy parametr wiersza poleceń i ignoruje resztę. Program Perla, który próbuje emulować, obsługuje wszystkie parametry wiersza poleceń. Więc przyjęta odpowiedź nawet nie odpowiada na pytanie. Inne odpowiedzi używają rozszerzeń bash, dodają niepotrzebne polecenia "cat", działają tylko w przypadku prostego powtarzania wejścia na wyjście lub są po prostu niepotrzebnie skomplikowane.
Jednak muszę dać mają trochę uznania, bo dali mi kilka pomysłów. Oto pełna odpowiedź:
#!/bin/sh
if [ $# = 0 ]
then
DEFAULT_INPUT_FILE=/dev/stdin
else
DEFAULT_INPUT_FILE=
fi
# Iterates over all parameters or /dev/stdin
for FILE in "$@" $DEFAULT_INPUT_FILE
do
while IFS= read -r LINE
do
# Do whatever you want with LINE here.
echo $LINE
done < "$FILE"
done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-05 17:11:08
Połączyłem wszystkie powyższe odpowiedzi i stworzyłem funkcję powłoki, która odpowiadałaby moim potrzebom. To jest z terminala cygwin z moich maszyn 2 Windows10, gdzie miałem udostępniony folder między nimi. Muszę być w stanie poradzić sobie z następującymi:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Jeśli podano konkretną nazwę pliku, muszę użyć tej samej nazwy pliku podczas kopiowania. Gdzie wejściowy strumień danych został przeportowany przez, następnie muszę wygenerować tymczasową nazwę pliku o godzina minuty i sekundy. Udostępniony folder mainfolder zawiera podfoldery dni tygodnia. To dla celów organizacyjnych.
Oto ostateczny scenariusz dla moich potrzeb:
tx ()
{
if [ $# -eq 0 ]; then
local TMP=/tmp/tx.$(date +'%H%M%S')
while IFS= read -r line; do
echo "$line"
done < /dev/stdin > $TMP
cp $TMP //$OTHER/stargate/$(date +'%a')/
rm -f $TMP
else
[ -r $1 ] && cp $1 //$OTHER/stargate/$(date +'%a')/ || echo "cannot read file"
fi
}
Jeśli Jest jakiś sposób, który możesz zobaczyć, aby jeszcze bardziej zoptymalizować to, chciałbym wiedzieć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-28 18:17:38
A może
for line in `cat`; do
something($line);
done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-05 21:03:39