Search code examples
bashsh

how to treat multiline text as only one line in cut command in sh or bash


I have this file named filename and the content is

export k="multiline_v"

for example

export k="kdk=dkdk
kdkdkdk=kdkd
ldldldsgg"

I want to use cut to get k and

my approach was this

cat filename | cut -d "=" -f 1

but it is treating it multiline and it returns

export aa
kdkdkd
kdkdkkd

How should I do this? I prefer to be able to use the same command in both sh and bash.

My goal is to get export k just from the first line - I just care about what exist in the first line


Solution

  • You haven't told us what OS you are using, but the GNU coreutils version of cut, which should be the default cut on most Linux systems, has a - option:

           -z, --zero-terminated
                  line delimiter is NUL, not newline
    

    So you can do:

    terdon@oregano foo $ cut -z -d= -f 1 filename 
    export kterdon@oregano foo $ 
    

    Note how my prompt appears right next to the output. That's because, since we're using -z to slurp the whole file, there is no trailing newline. So you could do:

    $ printf '%s\n' "$(cut -z -d= -f 1 filename)"
    bash: warning: command substitution: ignored null byte in input
    export k
    

    Now bash complains about the \0, which is added by cut -z. You can remove that too:

    $ printf '%s\n' "$(cut -z -d= -f 1 filename | tr -d '\0')"
    export k
    

    Of course, if you know it's always on the first line, you could simply do:

    $ head -n1 filename | cut -d= -f1
    export k
    

    Or, you could just use different tools:

    1. GNU grep

      $ grep -m1 -oP '^[^=]+' filename 
      export k
      
    2. Awk

      $ awk -F= '{print $1; exit}' filename 
      export k
      
    3. sed (note that this one only works if the = you want is on the first line)

      $ sed -nE 's/([^=]*)=.*/\1/p;q' filename 
      export k
      
    4. Perl

      $ perl -lne 'do{print $1; exit} if /([^=]*)=/' filename
      export k