#linux #bash #shell #unix #awk
#linux #bash #оболочка #unix #awk
Вопрос:
Это мой код:
#!/bin/sh
echo "ARGUMENTS COUNT : " $#
echo "ARGUMENTS LIST : " $*
dictionary=`awk '{ print $1 }'`
function()
{
for i in dictionary
do
for j in $*
do
if [ $j = $i ]
then
;
else
append
fi
done
done
}
append()
{
ls $j > dictionary1.txt
}
function
Мне нужно с помощью функций оболочки unix создать «словарь». Например: я пишу в аргументах слово по умолчанию, example hello
. Затем моя функция проверяет файл dictionary1
, существует ли это слово в файле. Если нет — добавьте это слово в файл, если оно уже существует — ничего не делайте.
По какой-то причине мой скрипт не работает. Когда я запускаю свой скрипт, он чего-то ждет, и все.
Что я делаю не так? Как я могу это исправить?
Комментарии:
1. Команда awk ожидает ввода и блокируется.
2. Если вы просто хотите проверить, было ли данное слово замечено ранее, ассоциативный массив bash может сделать это в памяти — файлы не нужны. Если вам нужно хранилище на диске, то, напротив, сортировка ваших входных данных позволит использовать алгоритм поиска на основе деления пополам, который значительно быстрее, чем то, что вы делаете сейчас.
3. КСТАТИ, для решения узких тактических вопросов см. shellcheck.net
4. Кроме того,
function
это ключевое слово в ksh-совместимых оболочках (которым стремится быть bash), поэтому вы не можете безопасно использовать его в качестве имени функции оболочки.5. Укажите ваши требования в вопросе! В противном случае мы не знаем, что делается из-за недостатка знаний об альтернативах, а что делается потому, что вас об этом явно спросили.
Ответ №1:
Реализация, которая пытается заботиться как о производительности, так и о корректности, может выглядеть следующим образом:
#!/usr/bin/env bash
# ^^^^- NOT sh; sh does not support [[ ]] or <(...)
addWords() {
local tempFile dictFile
tempFile=$(mktemp dictFile.XXXXXX) || return
dictFile=$1; shift
[[ -e "$dictFile" ]] || touch "$dictFile" || return
sort -um "$dictFile" <(printf '%sn' "$@" | sort -u) >"$tempFile"
mv -- "$tempFile" "$dictFile"
}
addWords myDict beta charlie delta alpha
addWords myDict charlie zulu
cat myDict
… имеет конечное состояние словаря:
alpha
beta
charlie
delta
zulu
… и он перечитывает входной файл только один раз при каждом addWords
вызове (независимо от того, сколько слов добавляется!), а не один раз для каждого добавляемого слова.
Комментарии:
1. Да, это работает идеально, но для меня это слишком сложно … : (
2. Если вы изучите методы и идиомы, которые в настоящее время выглядят «слишком сложными», они больше не будут слишком сложными. Если ваши преподаватели не хотят, чтобы вы учились самостоятельно или с помощью дополнительных ресурсов, то вам вообще не следует здесь находиться.
3. Да, я это понимаю. Но прежде всего, мне нужно хорошо разбираться в основах.
4. Все просто, если вы хорошо это понимаете…. Я планирую когда-нибудь туда попасть. 😉
5. Вызвав второе
sort -u
из короткого списка новых слов и предположив, что содержимое старого файла уже отсортировано, вы могли бы использовать слияние, чтобы значительно ускорить это, да? Это довольно ловко, Чарльз.
Ответ №2:
-
Не называйте функцию «function».
-
Не читайте и не просматривайте весь файл — все, что вам нужно, это знать, есть в нем слово или нет.
grep
делает это. -
ls
перечисляет файлы. Вы хотите отправить слово в файл, а не имя файла. используйтеecho
илиprintf
. -
sh
нетbash
. Используйтеbash
, если только нет явной причины не делать этого, и единственная причина в том, что он недоступен.
Попробуйте это:
#! /bin/env bash
checkWord() {
grep -qm 1 "$1" dictionary1.txt ||
echo "$1" >> dictionary1.txt
}
for wd
do checkWord "$wd"
done
Если это сработает, вы можете добавить больше структуры и проверки ошибок.
Ответ №3:
Вы можете удалить свою dictionary=awk...
строку (как уже упоминалось, она блокирует ожидание ввода) и просто grep ваш файл словаря для каждого аргумента, что-то вроде приведенного ниже :
for i in "$@"
do
if ! grep -qow "$i" dictionary1.txt
then
echo "$i" >> dictionary1.txt
fi
done
Комментарии:
1. Запускаем по одному
grep
на возможное добавление слова? Это смехотворно дорого по сравнению с простой сортировкой слиянием между (отсортированным) списком существующих слов и (отсортированным) списком новых слов. (Сохраняйте хранилище в порядке сортировки, и вам нужно отсортировать только новые слова — предположительно, более короткий подсписок).2. @Charles Я думаю, что это было самое простое решение, согласитесь, оно не самое эффективное.
Ответ №4:
С любым awk в любой оболочке на любом UNIX-сервере:
awk -v words="$*" '
BEGIN {
while ( (getline word < "dictionary1.txt") > 0 ) {
dict[word]
}
close("dictionary1.txt")
split(words,tmp)
for (i in tmp) {
word = tmp[i]
if ( !dict[word] ) {
newWords = newWords word ORS
}
}
printf "%s", newWords >> "dictionary1.txt"
exit
}'