Як отримати і PIPESTATUS, і вихід в bash script


9

Я намагаюся отримати останню дату модифікації файлу з цією командою

TM_LOCAL=`ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'`

TM_LOCAL має значення типу "2012-05-16 23:18" після виконання цього рядка

Я також хотів би перевірити PIPESTATUS, щоб перевірити, чи була помилка. Наприклад, якщо файл не існує, lsповертається 2. Але $?має значення 0, оскільки воно має значення повернення awk.

Якщо я запускаю цю команду самостійно, я можу перевірити повернене значення ls, переглянувши ${PIPESTATUS[0]}

ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'

Але $PIPESTATUSце не працює так, як я очікував, якщо призначити вихідну змінну, як у першому прикладі. У цьому випадку $PIPESTATUSмасив містить лише 1 елемент, який є таким же, як$?

Отже, питання полягає в тому, як я можу отримати обидва $PIPESTATUSта призначити вихідну змінну одночасно?

Відповіді:


8

Ви можете це зробити:

TM_LOCAL=$(ls -l --time-style=long-iso ~/.vimrc | \
             awk '{ print $6" "$7 }' ; exit ${PIPESTATUS[0]} )

Тоді $?буде код повернення з ls. Це не працює, якщо вам потрібен код повернення з більш ніж однієї з частин труби (але ви можете розділити конвеєр, якщо вихід не надто великий, як це є тут).

Ось досить дорогий спосіб отримати повний PIPESTATUSмасив та вихід. Не дуже елегантно, але нічого іншого не знайшли:

result=$(echo -e "a\nb\nc" | \
          ( cat ; exit 1 ) | \
          ( cat ; exit 42 ) ; echo ${PIPESTATUS[@]})
output=$(head -n -1 <<< "$result")
status=($(tail -n 1 <<< "$result"))
echo "Output:"
echo "$output"
echo "Results:"
echo "${status[@]}"

Що дає:

Output:
a
b
c
Results:
0 1 42

Ця робота в моєму випадку, але мені все одно цікаво, чи є спосіб отримати повний масив pipestatus та вихід.
Мустафа Сердар Шані

3

Використання set -o pipefailв , bashщоб отримати код виходу самого правого ненульового в централізованому послідовності команд , як $?. Від man bash:

Якщо встановлено, значення повернення трубопроводу - це значення останньої (правої) команди для виходу з ненульовим статусом або нульовим, якщо всі команди в трубопроводі успішно виходять. Цей параметр вимкнено за замовчуванням.

Тоді ви можете просто отримати доступ $?. Використовуйте, set +o pipefailщоб знову відключити.


2

Я припускаю, що тут проблема полягає в тому, що PIPESTATUS йде повністю, як тільки ви виконайте команду. Ви можете отримати повний масив PIPESTATUS в bash версії 2 або вище таким чином:

declare -a status
status=(${PIPESTATUS[@]})

Тоді доступу ${status[0]}, ${status[1]}і т.д.


2

Основна проблема "чого ви очікуєте" полягає в тому, що команда в зворотних котируваннях виконується в нижній частині; $PIPESTATUSіснує там, і статус, повернутий зm, дотримується тих же правил, що і якщо ви виконали один виконуваний (або сценарій оболонки). Статус команди backquote - це правий крайній ( awk) статус.

Щоб реалізувати те, що сказав @ Daniel Beck , встановіть pipefailпараметр у нижній частині так:

TM_LOCAL=`set -o pipefail; ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'` тепер статус, збережений у $?подальшому, буде статусом ls(якщо він не дорівнює нулю).

Однак, я думаю, явний if [ -f ~/.vimrc ];... тест був би читабельнішим.

Ви не можете отримати висновок у змінну і PIPESTATUSповернутись без тимчасового файлу для першого, або переведення останнього в рядок.


0

Я хотів відправити електронну пошту fron cron лише у тому випадку, якщо статус виходу не дорівнював нулю

Хитрість полягає в тому, що для отримання stdin для кінця трубопроводу потрібно помістити його в нижній корпус - але це, схоже, приховує значення PIPESTATUS ...

тестовий крон випльовує деякий вихід і виходить з 1 або 0.

./testcron | (test ${PIPESTATUS[0]} -ne 0 || mail -s "testcron output" paul)

ОНОВЛЕННЯ: PIPESTATUS не видно, поки команда конвеєра не буде виконана


0

Один із варіантів - перевірити наявність вашого файлу, перш ніж отримати його час модифікації із закликом до stat. Оскільки в statчасовій позначці повертається трохи більше, ніж ви хочете, ви можете обрізати її за допомогою розширення параметрів.

За допомогою GNU stat(наприклад, в Linux) ви можете запускати:

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -c '%y' ~/.vimrc 2>/dev/null)
TM_LOCAL=${TM_LOCAL%:*}  # Safe to do, even if stat fails

У Mac OS X та інших системах BSD statсинтаксис відрізняється і може визначати формат часу:

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' ~/.vimrc 2>/dev/null)

У відповіді GNU зараз ви говорите, що зміна $TM_LOCALє безпечною. Це безпечно лише в тому випадку, якщо ви очікували, що воно не має попереднього значення. Скажіть, що значення було раніше, 2020-02-27 17:14а ~/.vimrcфайлу немає . Ви б тоді 2020-02-27 17. Тому я б з'єднав ці дві лінії разом із додатковим &&або (бажано, оскільки це не так розбірливо) використовувати ifстрофу.
Адам Кац
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.