выберите столбцы из файлов и сохраните выходные данные

#bash #shell #for-loop #awk

#bash #оболочка #для цикла #awk

Вопрос:

я новичок в программировании.У меня много файлов в каталоге, как показано ниже: и каждый файл состоит из двух столбцов данных.

 TS.TST_X.1990-11-22
TS.TST_Y.1990-11-22
TS.TST_Z.1990-11-22

TS.TST_X.1990-12-30
TS.TST_Y.1990-12-30
TS.TST_Z.1990-12-30
  

Сначала я хочу выбрать только вторые столбцы всех файлов с одинаковыми именами (разница только в строках X, Y, Z) (TS.TST_X.1990-11-22, TS.TST_Y.1990-11-22, TS.TST_Z.1990-11-22) и хочу сохранить выходные данные в файле типа TSTST19901112

Аналогично для (TS.TST_X.1990-12-30, TS.TST_Y.1990-12-30, TS.TST_Z.1990-12-30 ) файлов также и хотите сохранить выходные данные, такие как TSTST19901230

Например: если файлы содержат, как показано ниже

 TS.TST_X.1990-11-22                 TS.TST_Y.1990-11-22               TS.TST_Z.1990-11-22
1  2                                 1   3.4                          1    2.1
2  5                                 2   2.4                          2    4.2
3  2                                 3   1.2                          3    1.0
4  4                                 4   2.4                          4    3.5
5  8                                 5   6.3                          5    1.8
  

Тогда выходной файл TSTST19901122 будет иметь вид

 2   3.4    2.1
5   2.4    4.2
2   1.2    1.0
4   2.4    3.5
8   6.3    1.8
  

я попробовал код

 #!/bin/sh
for file in /home/min/data/*
do
awk '{print $2}' $file 
done
  

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

Комментарии:

1. Используете ли вы sh или bash ? sh ( Bourne-shell ) обычно нет bash ( Bourne-again shell ).

2. Добро пожаловать в SO, спасибо, что показали свои попытки в виде кода. Не могли бы вы, пожалуйста, сообщить нам, хотите ли вы сравнить 1-й столбец всех файлов и сравнить их по значениям? Или мы могли бы просто объединить файлы, не проверяя 1-е поле? Пожалуйста, подтвердите один раз

3. @RavinderSingh13 мне вообще не нужен first coulmn..

4. @glkshu, я не упоминал о необходимости их использования в выходных данных. Я имел в виду, хотите ли вы сравнить значения 1-го столбца из файла в файл? Например, строка 1 file1 имеет 1 в столбце 1dt, а строка 2 file2 имеет 2 в 1-м столбце, в случае rat они должны быть объединены?

5. нет, сэр, мне не нужно

Ответ №1:

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

Вот онлайн : DEMO

 [akshay@db1 tmp]$ cat test.sh 
#!/usr/bin/env bash 

# use sort and uniq where field sep being dot, 
# we get unique date
while IFS= read -r f; do 

    # creates veriable like TS.TST_*.1990-11-22
    i=$(sed 's/_[^.]/_*/' <<<"$f"); 

    # modify outfile if you want any extension suffix etc
    outfile=$(sed 's/[^[:alnum:]]//g' <<<"$i")".txt";


    # filename expansion with unquoted variable
    # finally use awk to print whatever you want

    paste $i | awk 'NR>1{for(i=2; i<=NF; i =2)printf "%s%s", $(i), (i<NF ? OFS : ORS)}' >"$outfile"

done < <(printf '%sn' TS.TST* | sort -t'.' -u -nk3)

[akshay@db1 tmp]$ bash test.sh 
[akshay@db1 tmp]$ cat TSTST19901122.txt 
2  3.4  2.1
5  2.4  4.2
2  1.2  1.0
4  2.4  3.5
8  6.3  1.8
  

Ввод:

 [akshay@db1 tmp]$ ls TS.TST* -1
TS.TST_X.1990-11-22
TS.TST_Y.1990-11-22
TS.TST_Z.1990-11-22

[akshay@db1 tmp]$ for i in TS.TST*; do cat "$i"; done
TS.TST_X.1990-11-22 
1  2               
2  5              
3  2             
4  4          
5  8           
TS.TST_Y.1990-11-22
1   3.4
2   2.4
3   1.2
4   2.4
5   6.3
TS.TST_Z.1990-11-22
1    2.1
2    4.2
3    1.0
4    3.5
5    1.8
  

Комментарии:

1. Скопируйте / вставьте это в shellcheck, net , и он расскажет вам о некоторых проблемах. Возможно, он вам не расскажет о том, что for f in $(ls TS.TST* | ...); do ...; done должно быть while IFS= read -r f; do ... done < <(printf '%sn' TS.TST* | ...) или похожим (или лучше :-)!).

2. Спасибо, я исправлю, как только вернусь к своей системе. Теперь на мобильном

3. @EdMorton изменен, как вы предложили, однако у меня все еще есть переменная без кавычек

Ответ №2:

РЕДАКТИРОВАТЬ: поскольку OP упомянул в комментариях, что фактические имена файлов немного отличаются, поэтому добавьте решение в соответствии с этим здесь (поскольку в соответствии с OP существует только 3 типа файлов с разным годом и месяцем)..

 for file in TS.TST_BHE*
do
      year=${file/*./}
      year=${year//-/}
      yfile=${file/BHE/BHN}
      zfile=${file/BHE/BHZ}
      outfile="TSTST.$year"
      ##echo $file $yfile $zfile
      paste "$file" "$yfile" "$zfile"  | awk '{print $2,$4,$6}' > "$outfile"
done
  

Объяснение: добавление подробного объяснения выше.

 for file in TS.TST_BHE*
##Going through TS.TST_BHE named files in for loop here, where variable file will have its name in it.
do
      year=${file/*./}
      ##Creating year where removing everything till . here.
      year=${year//-/}
      ##Substituting all - with null in year variable.
      yfile=${file/BHE/BHN}
      ##Substituting BHE with BHN in file variable and saving it to yfile here.
      zfile=${file/BHE/BHZ}
      ##Substituting BHE with BHZ in file variable and saving it to zfile here.
      outfile="TSTST.$year"
      ##Creating outfile which has TSTST. with year variable value here.
      ##echo $file $yfile $zfile
      paste "$file" "$yfile" "$zfile"  | awk '{print $2,$4,$6}' > "$outfile"
      ##using paste to contenate values of 3 of the files(BHE BHN and BHZ) and printing only 2nd, 4th and 6th fields out of it.
done
  


Не могли бы вы, пожалуйста, попробовать следующее, основываясь на комментарии OP, что мы могли бы просто объединить Input_files без проверки значения 1-го столбца.

 for file in TS.TST_X*
do
      year=${file/*./}
      year=${year//-/}
      yfile=${file/X/Y}
      zfile=${file/X/Z}
      outfile="TSTST.$year"
      ###echo $file $yfile $zfile ##Just to print variable values(optional)
      paste "$file" "$yfile" "$zfile"  | awk '{print $2,$4,$6}' > "$outfile"
done
  

Для отображения образцов вывод будет следующим, выше будет сгенерировано имя файла d TS.TST_X.19901122 для показанных образцов.

 cat TSTST.19901122
2 3.4 2.1
5 2.4 4.2
2 1.2 1.0
4 2.4 3.5
8 6.3 1.8
  

Ответ №3:

Следующее воссоздание входных файлов:

 cat <<EOF >TS.TST_X.2000-11-22 
1  2               
2  5              
3  2             
4  4          
5  8       
EOF
cat <<EOF >TS.TST_Y.2000-11-22
1   3.4
2   2.4
3   1.2
4   2.4
5   6.3
EOF
cat <<EOF >TS.TST_Z.2000-11-22
1    2.1
2    4.2
3    1.0
4    3.5
5    1.8
EOF

cat <<EOF >TS.TST_X.1990-11-22 
1  2               
2  5              
3  2             
4  4          
5  8       
EOF
cat <<EOF >TS.TST_Y.1990-11-22
1   3.4
2   2.4
3   1.2
4   2.4
5   6.3
EOF
cat <<EOF >TS.TST_Z.1990-11-22
1    2.1
2    4.2
3    1.0
4    3.5
5    1.8
EOF
  

При запуске со следующим скриптом на repl:

 # get the filenames
find . -maxdepth 1 -name "TS.TST*" -printf "%fn" |
# meh, sort them, so it looks nice
sort |
# group files according to suffix after the dot
awk -F. '
    { a[$3]=a[$3]" "$0 }
    END{ for (i in a) print i, a[i] }
' |
# here we have: YYYY-MM-DD  filename1 filename2 filename3
# let's transform it into TSTSTYYYYMMDD filename{1,2,3}
sed -E 's/^([0-9]{4})-([0-9]{2})-([0-9]{2})/TSTST123/' |
while IFS=' ' read -r new f1 f2 f3; do
    # get second column from all files
    # if your awk doesn't sort files, they would have to be sorted here
    paste "$f1" "$f2" "$f3" | awk '{print $2,$4,$6}' > "$new"
done

# just output
for i in TSTST*; do echo "$i"; cat "$i"; done
  

Генерирует следующий вывод:

 TSTST19901122
2 3.4 2.1
5 2.4 4.2
2 1.2 1.0
4 2.4 3.5
8 6.3 1.8
TSTST20001122
2 3.4 2.1
5 2.4 4.2
2 1.2 1.0
4 2.4 3.5
8 6.3 1.8
  

Я бы посоветовал провести исследование основных команд оболочки. Прочитайте документацию о find . Прочитайте введение в awk и sed сценарии. Прочитайте хорошее введение в bash, узнайте, как перебирать, сортировать, объединять и фильтровать список файлов в bash. А также прочитайте, как читать поток построчно.