повторно использовать виртуальные файлы в скрипте bash - PullRequest
0 голосов
/ 25 октября 2019

Я пытаюсь запустить bash-скрипт, который выглядит примерно так:

#!/usr/bin/bash

only1=$(comm -23 $1 $2 | wc -l)
only2=$(comm -13 $1 $2 | wc -l)
common=$(comm -12 $1 $2 | wc -l)

echo -e "${only1} only in $1"
echo -e "${only2} only in $2"
echo -e "${common} in both"

Если я выполняю скрипт как script.sh file1 file2, он работает нормально. Тем не менее, если я использую его как script.sh <(grep 'foo' file1) <(grep 'foo' file2), произойдет сбой, потому что виртуальные файлы типа dev/fd/62 доступны только для первой команды (only1 в сценарии). Вывод:

262 only in /dev/fd/63
0 only in /dev/fd/62
0 in both

Есть ли способ сделать эти виртуальные файлы доступными для всех команд в сценарии?

1 Ответ

2 голосов
/ 25 октября 2019

Проблема здесь в том, что первый вызов comm будет читать до конца обоих входных файлов.

Поскольку вы хотели бы иметь возможность предоставлять каналы в качестве входных данных (вместо " real file), вам нужно будет прочитать входные данные только один раз, а затем предоставить их в качестве входных данных для последующих команд ... С конвейерами, как только данные читаются, они исчезают и не поступаютназад.

Например:

#!/bin/bash -eu

# cleanup temporary files on exit
trap 'rm ${TMP_FILE1:-} ${TMP_FILE2:-}' EXIT

TMP_FILE1=$(mktemp)
cat < $1 > $TMP_FILE1

TMP_FILE2=$(mktemp)
cat < $2 > $TMP_FILE2

only1=$(comm -23 $TMP_FILE1 $TMP_FILE2 | wc -l)
only2=$(comm -13 $TMP_FILE1 $TMP_FILE2 | wc -l)
common=$(comm -12 $TMP_FILE1 $TMP_FILE2 | wc -l)

echo -e "${only1} only in $1"
echo -e "${only2} only in $2"
echo -e "${common} in both"

Если ваши файлы достаточно малы, вы можете прочитать их в переменных:

#!/bin/bash -eu

FILE1=$( < $1 )
FILE2=$( < $2 )

only1=$(comm -23 <( echo "$FILE1" ) <( echo "$FILE2" ) | wc -l)
only2=$(comm -13 <( echo "$FILE1" ) <( echo "$FILE2" ) | wc -l)
common=$(comm -12 <( echo "$FILE1" ) <( echo "$FILE2" ) | wc -l)

echo -e "${only1} only in $1"
echo -e "${only2} only in $2"
echo -e "${common} in both"

Также обратите внимание, что comm работает только с отсортированными данными ... что означает, что вы, вероятно, захотите использовать sort на входах, если вы не полностью осведомлены о последствияхиспользуя несортированные входы.

sort < $1 > $TMP_FILE1
FILE1=$( sort < $1 )
...