3

File (myfile.txt) contains data as follows:

abc#ab1=23
nrt#
#clb1aX
amd#322

Desired Output:

abc
nrt
clb1ax
amd

I could do like this,

for i in `cat myfile.txt` 
do 
  s1=`echo $i | cut -d'#' -f1`; 
  s2=`echo $i | cut -d'#' -f2`; 
  if [ "$s1" == "" ]; then 
    echo "$s2" 
  else
    echo "$s1"
  fi;
done;

But is there anyway to do this without using for and if, like using awk or sed or cut or something else in single line?

  • 1
  • I could guess at what your intention is, but could you use some English words to spell it out for clarity? You want to ... hard-code a delimiter of #, and if there's nothing before a (presumed existant) #, then print what's after it.... until the next #? – Jeff Schaller May 11 '18 at 10:57
  • Roman's answer worked for me. My input will be having only two fields delimited by one hash. But fields value would be have some other special characters except hash. – Spike May 11 '18 at 11:19
8

Short awk solution:

awk -F'#' 'NF{ print ($1 != "" ? $1 : $2) }' file

The output:

abc
nrt
clb1aX
amd
  • assuming always at least one of $1 or $2 were not null. other wise it will cause empty lines for the input line like ###test – αғsнιη May 9 '18 at 10:19
  • @αғsнιη, that's obvious. Looking at the initial OP's algorithm it implies/expects only 2 fields, so the 2 fields are considered – RomanPerekhrest May 9 '18 at 10:43
2

Answer

sed -i "/^#/ { s/#\(.*\)/\1/; b }
        s/#.*//" myfile.txt

It can be joined in one line by adding the ; after the }, but it will be harder to read it like that.

Explanation

sed -i Keep the changes in the file, do not write them to stdout.

/^#/ - When sed is positioned on the line that starts with #.

s/#\(.*\)/\1/ - Replace the first occurence of #[everything] with [everything].

b - Stop the work on the current line and start working on the next one.
(Prevents s/#.*// command to be executed.)

s/#.*// - Remove the first occurence of #[everything].
(This will work for all lines, unless the previous b command exited early.)

myfile.txt File on which sed will perform.

  • Why it isn't working if I make it to single line? – Spike May 9 '18 at 10:08
  • 1
    You probably needed ;, I've updated the answer. Same thing applies now, if you want it in 1 line, just add the ; after }. – Iskustvo May 9 '18 at 10:09
  • 1
    this won't work for the line like ##test – αғsнιη May 9 '18 at 10:27
  • 1
    I know, it isn't specified in the test that it needs to work with it. That can easily be added. – Iskustvo May 9 '18 at 10:37
  • 1
    You can probably get away with a simpler regex using cut: sed 's/^#//' myfile.txt |cut -d'#' -f1 – ChatterOne May 9 '18 at 10:46
1

What if you had no fields with value or it was not just in the second column? then you would need.

awk -F'#' '{for(i=1; i<=NF; i++) if ($i != "") {print $i; break} }' infile

Given below sample:

abc#asd=123
nrt#
#clsdX
####
###here
acn#123

will give output:

abc
nrt
clsdX
here
acn

Or using sed and cut:

cut -d'#' -f1 <(sed 's/^#\+//; /^$/d' infile )
  • The s/^#\+// removes the leading hashes # (occurred one-or-more times)
  • The /^$/d removes produced empty line after above where a line was all hashes ##### or removes empty lines in file if there was any.
  • The cut -d'#' -f1 print the first field -f1 when fileds delimited by a hash -d'#'

Or sed only:

sed 's/^#\+//; /^$/d; s/^\([^#]*\)#.*/\1/' infile
  • This s/^\([^#]*\)#.*/\1/ captures a group of match start from begging of the line for anything until a first hash seen and just print it in result and ignore rest.
0

Using perl - assuming only single # in input as given in sample

$ perl -pe 's/[^#]\K#.*|^#//' ip.txt
abc
nrt
clb1aX
amd
  • [^#]\K#.* to delete all characters from first occurrence of # if there is a non# character preceding it
  • |^# otherwise, remove # from start of line


Same thing with sed

$ sed 's/\([^#]\)#.*\|^#/\1/' ip.txt
abc
nrt
clb1aX
amd
0

Another sed

sed 's/^#*\([^#]*\).*/\1/' infile

If you want to remove lines only with ####

sed 's/^#*\([^#]*\).*/\1/;/^$/d' infile
0
awk '{sub(/^#/,"")sub(/#/," &");print $1}' file

abc
nrt
clb1aX
amd

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.