2015-08-10 3 views
3

Я хочу повторить две переменные в одной строке.
Я хочу хранить 2015-03-04.01.Abhi_Ram.txt в переменной FILENAME и 10 в переменной COUNT и эхо их одновременно.Эхо несколько переменных в одной строке Bash

Sample.txt

2015-03-04.01.Abhi_Ram.txt 10
2015-03-04.02.Abhi_Ram.txt 70

Ниже код, который я придумал:

for line in `hadoop fs -cat sample.txt` 
do 

VAR="${line}" 
FILENAME=`echo ${VAR}|awk '{print $1}'` 
COUNT=`echo ${VAR}|awk '{print $2}'` 
COUNT_DT=`date "+%Y-%m-%d %H:%M:%S"` 
echo db"|"Abhi_Ram"|"record_count"|"${FILENAME}"||"${COUNT}"||"${COUNT_DT} >> output.txt 
done 

I want the output as: 

дб | Abhi_Ram | record_count | 2015-03-04.01.Abhi_Ram.txt || 10 || отметка времени дб | Abhi_Ram | record_count | 2015-03-04.02.Abhi_Ram.txt || 70 || Отметка времени

I'm getting the output as: 

дб | Abhi_Ram | record_count | 2015-03-04.01.Abhi_Ram.txt || || метка времени
дб | Abhi_Ram | record_count | 10 |||| метка времени
дб | Abhi_Ram | record_count | 2015-03-04.02.Abhi_Ram.txt |||| метка времени
дб | Abhi_Ram | record_count | 70 || || отметка времени

Может кто-нибудь Назовите меня тем, что мне не хватает?

+0

Почему вы вычисляете дату внутри цикла, когда она не использует какую-либо переменную? Это делает вашу петлю намного медленнее/дороже, чем в противном случае, если бы вы вывели наружный вызов «date», чтобы произойти только один раз до начала цикла. –

+1

Кроме того, если вы используете достаточно новый bash (4.1 или 4.2), для форматирования даты используется встроенная функция 'printf', при этом не используется внешняя команда' date'. –

ответ

6

Рассмотрим:

while read filename count 
do 
    count_dt=$(date "+%Y-%m-%d %H:%M:%S") 
    echo "db|Abhi_Ram|record_count|${filename}||${count}||${count_dt}" 
done <sample.txt >>output.txt 

Это создает файл:

$ cat output.txt 
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.json||10||2015-08-10 14:42:39 
db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.json||70||2015-08-10 14:42:39 

Примечания:

  1. Это рекомендуется использовать ниже или смешанный случай для переменных оболочки. Система использует переменные верхнего регистра, и вы не хотите случайно их перезаписывать.

  2. Многие двойные кавычки в заявлении echo не нужны. Вся строка вывода может быть внутри одной строки с двумя кавычками.

  3. Если вы хотите прочитать файл по одной строке за раз, безопаснее использовать конструкцию while read ... done <inputfile. Оператор read также позволяет легко определить переменные filename и count.

  4. Для замены команды многие предпочитают форму $(...) по форме обратного хода. Это связано с тем, что (a) $(...) делает визуальным отличием начало и конец подстановки команд, (b) форма $(...) хорошо гнездится, и (c) не все шрифты четко показывают обратные линии, отличные от обычных тиков. (Спасибо Chepner.)

  5. Для эффективности перенаправление на output.txt было перенесено в конец цикла. Таким образом, файл открывается и закрывается только один раз. (Спасибо Чарльз Даффи.)

  6. Если вам не нужен count_dt, обновленный с каждой отдельной записью, он может быть помещен перед циклом и установлен только один раз каждый раз обрабатывается sample.txt. Если у вас есть уточненный вариант Баша (не Mac OSX), то count_dt назначение может быть заменено (Спасибо Charles Duffy) с нативным заявлением Баша (не выкладывая требуется):

    printf -v count_dt '%(%Y-%m-%d %H:%M:%S)T' 
    
+0

Я предлагаю сделать это 'read -r', чтобы не отбрасывать литералы обратной косой черты. (Конечно, они не являются достоверными в именах файлов, но они _possible_). –

+0

Я также предложил бы поставить '> output.txt' на ** вне ** цикла, поэтому вы только открываете' output.txt' один раз, а не повторно открываете файл каждый раз, когда вы запускаете 'echo' , как это делается с '>> output.txt' в команде echo. –

+0

@CharlesDuffy Хорошая идея. Ответ обновляется, чтобы переместить перенаправление вне цикла. – John1024

1

John1024 объяснил, как это сделать правильно; Я хотел бы посмотреть, почему исходная версия не работает. Основная проблема заключается в том, что for петли над слов, не над линиями. Файл имеет два слова в каждой строке (имя файла и счетчик), поэтому он запускает цикл дважды в строке. Чтобы убедиться в этом, попробуйте:

for line in `hadoop fs -cat sample.txt` 
do 
    echo "$line" 
done 

... и он будет печатать что-то вроде:

2015-03-04.01.Abhi_Ram.txt 
10 
2015-03-04.02.Abhi_Ram.txt 
70 

... который не то, что вы хотите вообще. У него также есть некоторые другие неприятные причуды, например, если входной файл содержит слово «*», он вставляет список имен файлов в текущий каталог.

Подход while read ... done <file - это правильный способ перебора строк в сценарии оболочки. Просто случается, что также можно разделить каждую строку на поля без необходимости связываться с awk (в этом случае read filename count делает это).