Как использовать аргументы имени файла или значение по умолчанию к stdin, stdout (резюме)

Рассмотреть jstack. Не совсем достойный strace, больше a pstack- аналог, но по крайней мере даст Вам изображение снимка вовремя. Мог string'em вместе для получения сырой трассировки, если бы Вы имели к.

См. также предложения в этой статье SO: https://stackoverflow.com/questions/1025681/call-trace-in-java

5
09.10.2013, 09:35
5 ответов

Я сделал бы интенсивное использование из перенаправления ввода-вывода:

#!/bin/bash
[[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1
[[ $1 ]] && exec 3<$1 || exec 3<&0
[[ $2 ]] && exec 4>$2 || exec 4>&1
fgrep -v "stuff" <&3 >&4

Объяснение

  • [[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1

    Тест, если входной файл был указан как параметр командной строки и если файл существует.

  • [[ $1 ]] && exec 3<$1 || exec 3<&0

    Если $1 установлен, т.е. входной файл был указан, указанный файл открыт в дескрипторе файла 3, иначе stdin дублирован в дескрипторе файла 3.

  • [[ $2 ]] && exec 4>$2 || exec 4>&1

    Так же, если $2 установлен, т.е. выходной файл был указан, указанный файл открыт в дескрипторе файла 4, иначе stdout дублирован в дескрипторе файла 4.

  • fgrep -v "stuff" <&3 >&4

    Наконец fgrep вызывается, перенаправляя stdin и stdout к ранее дескрипторам файлов набора 3 и 4 соответственно.

Повторное открытие стандартного ввода и вывода

Если Вы предпочли бы не открывать промежуточные дескрипторы файлов, альтернатива должна заменить соответствие дескрипторов файлов stdin и stdout непосредственно с указанными входными и выходными файлами:

#!/bin/bash
[[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1
[[ $1 ]] && exec 0<$1
[[ $2 ]] && exec 1>$2
fgrep -v "stuff"

Недостаток с этим подходом состоит в том, что Вы освобождаете способность дифференцировать вывод от самого сценария от вывода команды, которая является целью для перенаправления. В исходном подходе можно направить вывод сценария к неизмененному stdin и stdout, который в свою очередь, возможно, был перенаправлен вызывающей стороной сценария. К указанным входным и выходным файлам можно было все еще получить доступ через соответствующие дескрипторы файлов, которые отличны от сценария stdin и stdout.

8
27.01.2020, 20:33
  • 1
    Это ведет себя больше как сценарий жемчуга, открывая новые файлы или вновь открывшись stdin и stdout с новыми дескрипторами файлов. –  ChuckCottrill 09.10.2013, 17:51
  • 2
    @ChuckCottrill Обновил ответ с примером повторного открытия stdin и stdout. Лично, я был бы обычно тихий предпочитать исходный подход по причинам, объясненным в обновленном ответе. –  Thomas Nyman 09.10.2013, 19:29
  • 3
    Согласованный, который полезен. Я искал что-то идиоматическое, которое я мог использовать для удобства 'перенести' некоторые сценарии. контрапункт –  ChuckCottrill 10.10.2013, 01:09

Как насчет:

  input="${1:-/dev/stdin}"
  output="${2:-/dev/stdout}"
  err="${3:-/dev/stderr}"

  foobar <"$input" >"$output" 2>"$err"

Необходимо отметить это /dev/std(in|out|err) не находятся в стандарте POSIX, таким образом, это будет только работать над системами, которые поддерживают эти специальные файлы.

Это также принимает нормальный вход: это не проверяет на существование файлов перед перенаправлением.

3
27.01.2020, 20:33
  • 1
    я рассмотрел использование/dev/std {in|out|err}, просто надеясь на что-то более умное... –  ChuckCottrill 10.10.2013, 01:07

если Вы не возражаете против этого, вывод всегда перенаправляется к stdout, можно использовать следующую остроту:

cat $1 |fgrep -v "stuff" | tee  
1
27.01.2020, 20:33
  • 1
    я больше ищу идиому, которая вновь открыла stdin и stdout, когда имена файлов даны. –  ChuckCottrill 09.10.2013, 17:53

Можно использовать exec <foo перенаправить вход сценария из файла foo, и аналогично exec >foo для вывода.

#!/bin/sh
set -e
if [ $# -ne 0 ]; then
  exec <"$1"
  shift
fi
if [ $# -ne 0 ]; then
  exec >"$1"
  shift
fi
fgrep -v "stuff"

Этот стиль является кратким, но не предоставляет себя хорошо подробному сообщению об ошибке.

1
27.01.2020, 20:33

Я не знаю, 'более ли это чисто', но здесь является некоторыми предложениями (это не тестируется код). Использование exec (на Thomas Nyman), может привести к проблемам безопасности и должен рассматриваться с осторожностью.

Первое место повторяющийся код в функции.

# die <message>
function die(){
    echo "Fatal error: $1, exiting ..." >&2
    exit 1
}

# is_file <file-path>
function is_file(){
    [[ -n "$1" && -f "$1" ]] && return 0
    die 'file not found'
}

Здесь, вместо использования fgrep, cat Ваш друг. Затем используйте избранный случай:

case $# in
    0) cat ;;                                  # accepts stdin to stdout.
    1) is_file "$1"; cat "$1" ;;               # puts $1 to stdout.
    2) is_file "$1"; cat "$1" > "$2" ;;        # puts $1 to $2.
    *) die 'too many arguments' ;;
esac

Другая альтернатива (который является чистым и очень компактным) должна загрузить инструкции в массиве и затем получить доступ к нему через значение $ #, что-то как указатель функции. Учитывая функцию is_file выше, код Bash - что-то как:

# action array.
readonly do_stuff=(
    'cat'                                  # 0 arg.
    'is_file \"$1\"; cat \"$1\"'           # 1 arg.
    'is_file \"$1\"; cat \"$1\" > \"$2\";' # 2 args.
)

# Main - just do:
[[ $# -le 2 ]] && ${do_stuff[$#]} || die 'too many arguments' 

Я не 100% на синтаксисе, но двойных кавычек нужно оставить. Лучше всего к переменным двойной кавычки, которые содержат пути к файлам.

Добавленное примечание, при записи в $2 - должно, вероятно, проверить, что файл не существует, или это будет перезаписано.

0
27.01.2020, 20:33

Теги

Похожие вопросы