Трубопровод для вывода цикла предотвращает модификацию локальной переменной

11

Я пытаюсь написать простую функцию bash, которая принимает в качестве аргументов несколько файлов и / или каталогов. Должно:

  1. Полностью уточните имена файлов.
  2. Сортировать их.
  3. Удалить дубликаты.
  4. Распечатайте все, что на самом деле существует.
  5. Вернуть количество несуществующих файлов.

У меня есть скрипт, который почти делает то, что я хочу, но падает на сортировку. Возвращаемое значение скрипта в его текущем состоянии является правильным, но вывод не является (несортированный и дублирует). Если я раскомментирую | sort -uоператор, как указано, вывод верен, но возвращаемое значение всегда 0.

NB. Более простые решения для решения проблемы приветствуются, но вопрос в том, почему это происходит в моем коде. То есть почему добавление канала, по-видимому, останавливает сценарий, увеличивающий переменную r?

Вот сценарий:

function uniqfile
{
    local r=0 

    for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done #| sort -u    ## remove that comment

    return $r
}
TJM
источник
Просто небольшое наблюдение. Вы можете уменьшить for arg in "$@"до for arg. "Если 'в словах ...;' нет, тогда предполагается "в" $ @ "." - помощь для
manatwork

Ответы:

15

Это хорошо известная ошибка в bash, благодаря этой функции :

Каждая команда в конвейере выполняется как отдельный процесс (т. Е. В подоболочке).

так что измененные переменные являются локальными для подоболочки и не видны ни разу в родительском.

Чтобы избежать этого, перефразируйте ваш код, чтобы избежать конвейера, с подстановкой процесса:

 for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done > >(sort -u)
enzotib
источник
Спасибо. Замечательно. Интересно, не могли бы вы сказать мне название >(..command..)конструкции? Я думаю, что знаю, как это работает, но чувствую, что мне следует немного почитать.
TJM
2
@tjm: это называется процессом замещения
enzotib
Подстановка процессов в Bash имеет много форм: tldp.org/LDP/abs/html/process-sub.html
ОДС
Замена процесса - это форма межпроцессного взаимодействия, которая позволяет вводу или выводу команды отображаться в виде файла. Команда подставляется в командной строке, где обычно происходит имя файла , командной оболочкой. Это позволяет программам, которые обычно только принимают файлы, непосредственно читать или записывать в другую программу.
Нобар
3

Эти | sort -uсилы предшествующий бит (так что весь цикл) для запуска в подпроцесс (Баш нужен «STDOUT» для перенаправления в sort«STDIN». (Интернет , кажется, думает kshи bashобрабатывать этот случай немного по- другому .. первый или последний команда в последовательности конвейера попадает в подоболочку?)

В этой теме рассматривается аналогичная проблема, и в конце ее вы найдете аккуратное решение: http://ubuntuforums.org/showthread.php?t=312017.

выдержка
    #!/bin/bash
    exec 3< <(du | sort -n)  

    n=0
    while read size dir; do
      [ $size -gt 1000 ] && ((n++))
    done <&3
    exec 3<&-

    echo "Found $n too big files"
PT
источник