Чтение в файле построчно с Bash
Я создаю скрипт bash для чтения файла построчно, который форматируется позже, чтобы упорядочить его по имени, а затем по дате. Я не могу понять, почему этот код не работает в настоящее время, хотя никаких ошибок не появляется, хотя я пробовал с переменными имени файла ввода и вывода самостоятельно, с помощью средства поиска каталогов и команды экспорта.
export inputfilename="employees.txt"
export outputfilename="branch.txt"
directoryinput=$(find -name $inputfilename)
directoryoutput=$(find -name $outputfilename)
n=1
if [[ -f "$directoryinput" ]]; then
while read line; do
echo "$line"
n=$((n+1))
done < "$directoryoutput"
else
echo "Input file does not exist. Please create a employees.txt file"
fi
Вся помощь очень ценится, спасибо! ПРИМЕЧАНИЕ: Как заметили люди, я забыл добавить знак $ на передачу данных в файл, но это было только при копировании моего кода, у меня действительно есть знак $ в моем реальном приложении, и все равно нет результата
2 ответа
Чтение в файле построчно с Bash
Лучший идиоматичный способ читать файл построчно:
while IFS= read -r line; do
// parse line
printf "%s" "$line"
done < "file"
Больше на эту тему можно найти на bashfaq
Однако не читайте файлы в bash построчно. Вы можете (хорошо, почти) всегда не читать поток построчно в bash. Строковое чтение файла в bash чрезвычайно медленное и не должно выполняться. Для простых случаев все инструменты Unix с помощью xargs
или же parallel
можно использовать, для более сложных awk
а также datamesh
используются.
done < "directoryoutput"
Код не работает, потому что вы передаете свой цикл while в качестве входных данных для стандартного ввода содержимого файла с именем directoryoutput
, Так как такого файла не существует, ваш скрипт завершается ошибкой.
directoryoutput=$(find -name $outputfilename)
Можно просто добавить значение переменной с помощью новой строки, добавленной к циклу чтения, используя конструкцию HERE-string:
done <<< "$directoryoutput"
directoryinput=$(find -name $inputfilename)
if [[ -f "$directoryinput" ]]
Это нормально, если у вас есть только один файл с именем $inputfilename
в вашем каталоге. Также нет смысла искать файл, а затем проверять его наличие. В случае большего количества файлов find возвращает список имен, разделенных новой строкой. Однако небольшая проверка if [ "$(printf "$directoryinput" | wc -l)" -eq 1 ]
или используя find -name $inputfilename | head -n1
Я думаю, что будет лучше.
while read line; do echo "$line" n=$((n+1)) done < "directoryoutput"
Намерение довольно ясно здесь. Это просто:
n=$(<directoryoutput wc -l)
cat "directoryoutput"
Кроме этого while read line
убрал завершающие и ведущие символы новой строки и зависит от IFS.
Также не забывайте указывать в кавычках ваши переменные, если у вас нет причин не делать этого.
Посмотрите на shellcheck, который может найти наиболее распространенные ошибки в скриптах.
Я бы сделал это больше так:
inputfilename="employees.txt"
outputfilename="branch.txt"
directoryinput=$(find . -name "$inputfilename")
directoryinput_cnt=$(printf "%s\n" "$directoryinput" | wc -l)
if [ "$directoryinput_cnt" -eq 0 ]; then
echo "Input file does not exist. Please create a '$inputfilename' file" >&2
exit 1
elif [ "$directoryinput_cnt" -gt 1 ]; then
echo "Multiple file named '$inputfilename' exists in the current path" >&2
exit 1
fi
directoryoutput=$(find . -name "$outputfilename")
directoryoutput_cnt=$(printf "%s\n" "$directoryoutput" | wc -l)
if [ "$directoryoutput_cnt" -eq 0 ]; then
echo "Input file does not exist. Please create a '$outputfilename' file" >&2
exit 1
elif [ "$directoryoutput_cnt" -gt 1 ]; then
echo "Multiple file named '$outputfilename' exists in the current path" >&2
exit 1
fi
cat "$directoryoutput"
n=$(<"$directoryoutput" wc -l)
Я думаю, вам нужно <<< до вашего пути / имени файла var после того, как сделано. Или, может быть <<< "$( cat $filename)"
Например, вот процедура для чтения вывода df -h в некоторые глобальные массивы:
declare -a FileSystem
declare -a PctUsed
declare -i Percent #typeset Percent to get rid of warning about integer messages
get_data() {
printf "Enter percentage threshold to report : "
read Threshold
i=0
while read FS SizeGB UsedGB AvailableGB Pct MountPoint
do
Percent=$(echo "$Pct"|tr -d "%" )
if [ "$Threshold" -le "$Percent" ]
then
FileSystem[$i]="$FS"
PctUsed[$i]=$Percent
(( i+=1 ))
fi
done <<< "$( df -h )"
} #end get_data