जैसा कि नीचे बताया गया है, हमें अलग-अलग लंबाई की इनपुट फ़ाइल मिल रही है। पाठ अलग-अलग लंबाई का है।

इनपुट फ़ाइल:

ID|Text
1|name1=value1;name3;name4=value2;name5=value5
2|name1=value1;name2=value2;name6=;name7=value7;name8=value8

यहां टेक्स्ट ने वैल्यू पेयर को कंटेंट के रूप में नामित किया है और यह अलग-अलग लंबाई का है। कृपया ध्यान दें कि टेक्स्ट कॉलम में नाम में सेमी कोलन हो सकता है। हम इनपुट को पार्स करने की कोशिश कर रहे हैं लेकिन हम इसे एडब्ल्यूके या बाश के माध्यम से संभालने में सक्षम नहीं हैं

वांछित आउटपुट:

1|name1=value1
1|name3;name4=value2
1|name5=value5
2|name1=value1
2|name2=value2
2|name6=
2|name7=value7
2|name8=value8

नीचे दिया गया कोड आईडी = 2 के लिए काम करता है, लेकिन आईडी = 1 के लिए नहीं

echo "2|name1=value1;name2=value2;name6=;name7=value7;name8=value8" | while IFS="|"; read id text;do dsc=`echo $text|tr ';' '\n'`;echo "$dsc" >tmp;done
cat tmp
2|name1=value1
2|name2=value2
2|name6=
2|name7=value7
2|name8=value8
echo "1|name1=value1;name3;name4=value2;name5=value5" | while IFS="|"; read id text;do dsc=`echo $text|tr ';' '\n'`;echo "$dsc" >tmp;sed -i "s/^/${id}\|/g" tmp;done
cat tmp
1|name1=value1
1|name3
1|name4=value2
1|name5=value5

कोई भी मदद बहुत ही सराहनीय होगी।

3
seanarcher7 5 नवम्बर 2020, 16:01

5 जवाब

सबसे बढ़िया उत्तर

क्या आप जीएनयू awk में दिखाए गए नमूनों के साथ इसके नए संस्करण के साथ निम्नलिखित, लिखित और परीक्षण करने का प्रयास कर सकते हैं। चूँकि OP का awk संस्करण पुराना है, इसलिए यदि किसी के पास awk का पुराना संस्करण है तो उसे awk --re-interval में बदलने का प्रयास करें

awk '
BEGIN{
  FS=OFS="|"
}
FNR==1{ next }
{
  first=$1
  while(match($0,/(name[0-9]+;?){1,}=(value[0-9]+)?/)){
    print first,substr($0,RSTART,RLENGTH)
    $0=substr($0,RSTART+RLENGTH)
  }
}'  Input_file

आउटपुट निम्नानुसार होगा।

1|name1=value1
1|name3;name4=value2
1|name5=value5
2|name1=value1
2|name2=value2
2|name6=
2|name7=value7
2|name8=value8

स्पष्टीकरण: ऊपर के लिए विस्तृत विवरण जोड़ना (निम्नलिखित केवल स्पष्टीकरण के उद्देश्य से है)।

awk '                                        ##Starting awk program from here.
BEGIN{                                       ##Starting BEGIN section from here.
  FS=OFS="|"                                 ##Setting FS and OFS wiht | here.
}
FNR==1{ next }                               ##If line is first line then go next, do not print anything.
{
  first=$1                                   ##Creating first and setting as first field here.
  while(match($0,/(name[0-9]+;?){1,}=(value[0-9]+)?/)){
##Running while loop which has match which has a regex of matching name and value all mentioned permutations and combinations.
    print first,substr($0,RSTART,RLENGTH)    ##Printing first and sub string(currently matched one)
    $0=substr($0,RSTART+RLENGTH)             ##Saving rest of the line into current line.
  }
}' Input_file                                ##Mentioning Input_file name here.
2
RavinderSingh13 5 नवम्बर 2020, 17:37
BEGIN {FS = "[;|]"}
FNR == 1 {next}
{
    sep = $1 "|"
    for (i = 2; i <= NF; ++i) {
        printf "%s%s", sep, $i
        sep = ($i ~ /=/ ? ORS $1 "|" : ";")
    }
    print ""
}

आउटपुट (कोने के मामलों वाली एक इनपुट फ़ाइल दी गई है):

$ cat test_file
ID|Text
1|name1=value1;name3;name4=value2;Test1
2|Test2;name2=value2;name6=;name7=value7;Test3
$ awk -f prog.awk test_file
1|name1=value1
1|name3;name4=value2
1|Test1
2|Test2;name2=value2
2|name6=
2|name7=value7
2|Test3
0
rowboat 5 नवम्बर 2020, 18:30

आपके पास कुछ अच्छे उत्तर हैं और एक स्वीकृत पहले से ही है। यहाँ एक बहुत छोटा gnu awk कमांड है जो काम भी कर सकता है:

awk -F '|' 'NR > 1 {
   for (s=$2; match(s, /([^=]+=[^;]*)(;|$)/, m); s=substr(s, RLENGTH+1))
      print $1 FS m[1]      
}' file.txt
1|name1=value1
1|name3;name4=value2
1|name5=value5
2|name1=value1
2|name2=value2
2|name6=
2|name7=value7
2|name8=value8
0
anubhava 6 नवम्बर 2020, 00:21

एक बैश समाधान:

#!/usr/bin/env bash

while IFS=\| read -r id text || [ -n "$id" ]; do
  IFS=\; read -r -a kv_arr < <(printf %s "$text")
  printf "$id|%s\\n" "${kv_arr[@]}"
done < <(tail -n +2 a.txt)

एक सादा पॉज़िक्स खोल समाधान:

#!/usr/bin/env sh

# Chop the header line from the input file
tail -n +2 a.txt |
# While reading id and text Fields Separated by vertical bar
while IFS=\| read -r id text || [ -n "$id" ]; do
  # Sets the separator to a semicolon
  IFS=\;
  # Print each semicolon separated field formatted on
  # its own line with the ID
  # shellcheck disable=SC2086 # Explicit split on semicolon
  printf "$id|%s\\n" $text
done

इनपुट a.txt:

ID|Text
1|name1=value1;name3;name4=value2;name5=value5
2|name1=value1;name2=value2;name6=;name7=value7;name8=value8

आउटपुट:

1|name1=value1
1|name3
1|name4=value2
1|name5=value5
2|name1=value1
2|name2=value2
2|name6=
2|name7=value7
2|name8=value8
1
Léa Gris 5 नवम्बर 2020, 17:30

नमूना डेटा:

$ cat name.dat
ID|Text
1|name1=value1;name3;name4=value2;name5=value5
2|name1=value1;name2=value2;name6=;name7=value7;name8=value8

एक awk समाधान:

awk -F"[|;]" '                                                           # use "|" and ";" as input field delimiters
FNR==1 { next }                                                          # skip header line
       { pfx=$1 "|"                                                      # set output prefix to field 1 + "|"
         printpfx=1                                                      # set flag to print prefix

         for ( i=2 ; i<=NF ; i++ )                                       # for fields 2 to NF
             {
               if ( printpfx)     { printf "%s",   pfx  ; printpfx=0 }   # if print flag == 1 then print prefix and clear flag
               if ( $(i)  ~ /=/ ) { printf "%s\n", $(i) ; printpfx=1 }   # if current field contains "=" then print it, end this line of output, reset print flag == 1
               if ( $(i) !~ /=/ ) { printf "%s;",  $(i) }                # if current field does not contain "=" then print it and include a ";" suffix
             }
       }
' name.dat

उपरोक्त उत्पन्न करता है:

1|name1=value1
1|name3;name4=value2
1|name5=value5
2|name1=value1
2|name2=value2
2|name6=
2|name7=value7
2|name8=value8
2
markp-fuso 5 नवम्बर 2020, 17:10