Трубопровід для виходу з циклу запобігає локальній модифікації змінної


11

Я намагаюся написати просту функцію bash, яка бере в якості своїх аргументів ряд файлів та / або каталогів. Слід:

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

У мене є сценарій, який майже робить те, що я хочу, але падає на сортування. Повернене значення сценарію в такому вигляді є правильним, але вихід не є (несортований і дублюється). Якщо я відменюю | sort -uтвердження, як зазначено, вихід правильний, але значення повернення завжди 0.

Примітка. Простіші рішення для вирішення проблеми вітаються, але питання справді полягає в тому, чому це відбувається в коді, який у мене є. Тобто, чому додавання труби, здавалося б, зупиняє збільшення сценарію, збільшуючи змінну r?

Ось сценарій:

function uniqfile
{
    local r=0 

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

    done #| sort -u    ## remove that comment

    return $r
}

Просто невелике спостереження. Можна зменшити for arg in "$@"до for arg. "Якщо" у СЛОВАх ...; " немає, тоді "в" $ @ "'передбачається." - допомога для
манатура

Відповіді:


15

Це добре відомий підводний камінь, завдяки цій особливості :

Кожна команда в конвеєрі виконується як окремий процес (тобто в підпакеті).

так що модифіковані змінні є локальними для підрозділу і не відображаються один раз у батьківському.

Щоб уникнути цього, переформулюйте код, щоб уникнути конвеєра, із заміною процесу:

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

    done > >(sort -u)

Дякую. Це чудово. Цікаво, чи можете ви сказати мені назву >(..command..)конструкції. Я думаю, що я знаю, як це працює, але відчуваю, що мені варто трохи прочитати.
TJM

2
@tjm: це називається процес заміщення
enzotib

Заміна процесу в Bash має багато форм: tldp.org/LDP/abs/html/process-sub.html
slm

Заміна процесу - це форма міжпроцесового зв'язку, яка дозволяє введення або виведення команди відображатись як файл. Команда замінюється в рядку, де зазвичай виникає ім'я файлу , оболонкою команди. Це дозволяє програмам, які зазвичай приймають лише файли, безпосередньо читати або записувати в іншу програму.
nobar

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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.