Как создать «словарь» с помощью функций оболочки?

#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
}'