Дамп содержимого переменной в файл во время выполнения скрипта в bash

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

mytime=$(time (for i in {1..3}; do curl -s -w '\n' -XPOST -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode query='select distinct ?Concept where {[] a ?Concept} LIMIT 100' http://143.233.226.61:443/sparql > /dev/null; done) 2>&1 1>/dev/null)
2
15.09.2019, 15:26
3 ответа

trap break INT перед циклом:

hashes=
trap break INT
for file in *; do
  hashes+=$(md5sum -- "$file")$'\n'
done
trap - INT

echo "$hashes" > hashes.txt

Я исправил некоторые сомнительные вещи в вашем скрипте ($(ls),"\n").

FWIW, такой "нелокальный разрыв" не работает в mkshили yash, но работает в bash, dash, zshи ksh93.

2
27.01.2020, 21:55
trap ctrl_c INT

ctrl_c() {
    echo "$hashes" > hashes.txt
    exit 0
}

Кстати, я бы не использовал lsдля получения списка файлов, а что-то вроде for file in *; do.

3
27.01.2020, 21:55

Вы никогда не должны использовать выходные данные lsв качестве входных данных для другой программы. Это не работает (для любого определения «работы», включающего понятия надежности или безопасности ), и нет никогда никакой необходимости делать это, потому что оболочка выполняет подстановку (т.е. расширение подстановочных знаков )выполняет работу, которую вы пытаетесь выполнить с помощью mis -с использованием ls. См. Почему не разборls(и что делать вместо )? .

Если вы должны сделать что-то подобное, используйте find... -exec {} +или find... -print0 | xargs -0r..., а неls-любой из них действительно будет работать и работать безопасно, независимо от того, какие символы есть в именах файлов.

Ваш цикл forдолжен быть записан как:

for file in *; do
 ...
done

Вам даже не нужен цикл for, если только вы не собираетесь делать что-то еще с каждым $fileвнутри цикла.

Вот несколько альтернативных способов сделать то, что делает ваш цикл for, сохраняя вывод md5sumв массив с именем hashesи затем выводя его:

  1. с помощьюprintf:

    $ hashes=( $( md5sum * ) )
    $ printf '%s  %s\n' "${hashes[@]}" > hashes.txt
    $ cat hashes.txt
    b026324c6904b2a9cb4b88d6d61c81d1  file.1
    26ab0db90d72e28ad0ba1e22ee510510  file.2
    6d7fce9fee471194aa8b5b6e47267f03  file.3
    

    Обратите внимание, что в строке формата printfесть два %s, разделенных двумя пробелами. Это даст тот же результат, что и сам md5sum.

    Кстати, вы можете увидеть, как записи хранятся в массиве с помощьюtypeset -p:

    $ typeset -p hashes
    declare -a hashes=([0]="b026324c6904b2a9cb4b88d6d61c81d1" [1]="file.1"
    [2]="26ab0db90d72e28ad0ba1e22ee510510" [3]="file.2"
    [4]="6d7fce9fee471194aa8b5b6e47267f03" [5]="file.3")
    

    Оболочка разделила вывод md5sumна слова (, как определено значением переменной оболочки $IFS), и поместила каждое «слово» в отдельный элемент массива.

  2. с помощьюtee:

    $ hashes=( $( md5sum * | tee hashes.txt) )
    $ cat hashes.txt
    b026324c6904b2a9cb4b88d6d61c81d1  file.1
    26ab0db90d72e28ad0ba1e22ee510510  file.2
    6d7fce9fee471194aa8b5b6e47267f03  file.3
    

Зная это, ответ-ловушка Лассе Климана может быть записан как:

trap ctrl_c INT

ctrl_c() {
    printf '%s  %s\n' "${hashes[@]}" > hashes.txt
    exit 0
}

Впрочем, здесь даже ловушка не нужна. md5sumс teeсделают то, что вы хотите -, т.е.одновременно заполнить $hashesИ файл hashes.txt.

Или, если вы не хотите использовать массив:

$ for file in *; do
    hashes+="$(md5sum "$file" | tee -a hashes.txt)"$'\n'
  done

$ echo "$hashes"
b026324c6904b2a9cb4b88d6d61c81d1  file.1
26ab0db90d72e28ad0ba1e22ee510510  file.2
6d7fce9fee471194aa8b5b6e47267f03  file.3

Здесь мы используем опцию tee's -a(--append), потому что мы запускаем md5sumв цикле и не хотим, чтобы каждая итерация перезаписывала файл hashes.txt.

Примечание :Это всегда будет иметь дополнительную пустую строку в конце строки $hashes, увеличивая количество строк на 1. Этого не будет при использовании массива.

0
27.01.2020, 21:55

Теги

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