extract number from string - sed

I have a string ABCD20110420.txt and I want to extract the date out of it. Expected 2011-04-20
I can use replace to remove the text part, but how do I insert the "-" ?
# echo "ABCD20110420.txt" | replace 'ABCD' '' | replace '.txt' ''
20110420

echo "ABCD20110420.txt" | sed -e 's/ABCD//' -e 's/.txt//' -e 's/\(....\)\(..\)\(..\)/\1-\2-\3/'
Read: sed FAQ

Just use the shell (bash)
$> file=ABCD20110420.txt
$> echo "${file//[^0-9]/}"
20110420
$> file="${file//[^0-9]/}"
$> echo $file
20110420
$> echo ${file:0:4}-${file:4:2}-${file:6:2}
2011-04-20
The above is applicable to files like your sample. If you have files like A1BCD20110420.txt, then will not work.
For that case,
$> file=A1BCD20110420.txt
$> echo ${file%.*} #get rid of .txt
A1BCD20110420
$> file=${file%.*}
$> echo "2011${file#*2011}"
20110420
Or you can use regular expression (Bash 3.2+)
$> file=ABCD20110420.txt
$> [[ $file =~ ^.*(2011)([0-9][0-9])([0-9][0-9])\.*$ ]]
$> echo ${BASH_REMATCH[1]}
2011
$> echo ${BASH_REMATCH[2]}
04
$> echo ${BASH_REMATCH[3]}
20

echo "ABCD20110420.txt" | sed -r 's/.+([0-9]{4})([0-9]{2})([0-9]{2}).+/\1-\2-\3/'

$ file=ABCD20110420.txt
$ echo "$file" | sed -e 's/^[A-Za-z]*\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\.txt$/\1-\2-\3/'
This only requires a single call to sed.

echo "ABCD20110420.txt" | sed -r 's/.{4}(.{4})(.{2})(.{2}).txt/\1-\2-\3/'

Related

wc -c gives one more than I expected, why is that?

echo '2003'| wc -c
I thought it would give me 4, but it turned to be 5, what is that additional byte?
Because echo will get a new line.
echo "2014" | wc -c
it will get 5
printf "2014" | wc -c
it will get 4 where printf will not add a new line.
echo contains a built-in switch, -n, to remove newline. So running:
echo -n "2021" | wc -c
Will output the expected 4.
echo adds new line which is causing the issue.
As mentioned by "KyChen", you can use printf or:
a="2014 ;
echo $a |awk '{print length}'

assign actions to one sed address simultaneously for match and non-match

My sed command line script looks like
echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p; /^...$/! q1'
I want the script to succeed (return-code 0) if there are exactly 3 letters left, and to fail otherwise.
The slightly nagging part is that I have to duplicate the address /^...$/.
I was hoping for something like
echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p ! q1'
but that doesn't work, at least not with that syntax.
You can use // to represent previously used regex
$ echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p; //! q1'
$ echo $?
1
$ echo "b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p; //! q1'
bcd
$ echo $?
0
Alternatively, you can use b command to start next cycle
$ echo "b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/{p;b}; q1'
bcd
$ echo $?
0
$ echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/{p;b}; q1'
$ echo $?
1
This syntax will probably work with GNU sed only. See manual for details

Remove eval in an existing code

I am working on an existing shell script code which has eval. I feel like that eval is unnecessary here and wanted to remove to avoid Injection.
Could you please check the code and advise why there is an eval in the code.
FILE_PATH=`echo $1 | awk '{ print $10 }' | cut -f2 -d'"'
FILE_PATH=`(eval "echo ${FILE_PATH}")`
if $1 is something like that ---"~/tttttttt.txt.
FILE_PATH will be ~/tttttttt.txt without eval.
but with eval;
FILE_PATH will be /home/user/tttttttt.txt
#!/bin/bash
path='-----"~/tttttttt.txt'
FILE_PATH=`echo $path | awk '{ print $1 }' | cut -f2 -d'"'`
echo "${FILE_PATH}"
ls -lart ${FILE_PATH}
FILE_PATH=`(eval "echo ${FILE_PATH}")`
echo $FILE_PATH
ls -lart ${FILE_PATH}
if run above script, output:
~/tttttttt.txt
ls: cannot access ~/tttttttt.txt: No such file or directory
/home/user/tttttttt.txt
-rw-rw-r-- 1 user user 0 Aug 26 15:54 /home/user/tttttttt.txt

Pattern extraction using SED or AWK

How do I extract 68 from v1+r0.68?
Using awk, returns everything after the last '.'
echo "v1+r0.68" | awk -F. '{print $NF}'
Using sed to get the number after the last dot:
echo 'v1+r0.68' | sed 's/.*[.]\([0-9][0-9]*\)$/\1/'
grep is good at extracting things:
kent$ echo " v1+r0.68"|grep -oE "[0-9]+$"
68
Match the digit string before the end of the line using grep:
$ echo 'v1+r0.68' | grep -Eo '[0-9]+$'
68
Or match any digits after a .
$ echo 'v1+r0.68' | grep -Po '(?<=\.)\d+'
68
Print everything after the . with awk:
echo "v1+r0.68" | awk -F. '{print $NF}'
68
Substitute everything before the . with sed:
echo "v1+r0.68" | sed 's/.*\.//'
68
type man grep
and you will see
...
-o, --only-matching
Show only the part of a matching line that matches PATTERN.
then type echo 'v1+r0.68' | grep -o '68'
if you want it any where special do:
echo 'v1+r0.68' | grep -o '68' > anyWhereSpecial.file_ending

Using grep with sed and writing a new file based on the results

I'm very new to some of the command line utilities and have been looking for a while for a command that would accomplish my goal.
The goal is to find files that contain a string of text, replace it with a new string, and then write the results to a file that is named the same as the original, but in a different directory.
Obviously this is not working, so I am asking how you who know about this stuff would go about it.
grep -rl 'stringToFind' *.* | sed 's|oldString|newString|g' < fileNameFromGrep > ./new/fileNameFromGrep
Thanks for your input!
John
for f in "`find /YOUR/SEARCH/DIR/ROOT -type f -exec fgrep -l 'stirngToFind' \{\} \;`" ; do
sed 's|oldString|newString|g' < "${f} > ./new/"${f}
done
Will do it for you.
If you have spaces in filenames:
OLDIFS=$IFS
IFS=''
find /PATH -print0 -type f | while read -r -d $'' file
do
fgrep -l 'stirngToFind' "$file" && \
sed 's|oldString|newString|g' < "${file} > ./new/"${file}
done
IFS=$OLDIFS
#!/bin/bash
for file in *; do
if grep -qF 'stringToFind' "$file"; then
sed 's/oldString/newString/g' "$file" > "./new/$file"
fi
done
for file in path/to/dir/*
do
grep -q 'pattern' "$file" > /dev/null
if [ $? == 0 ]; then
sed 's/oldString/newString/g' "$file" > /path/to/newdir/"$file"
fi
done
You try:
sed -ie "s/oldString/newString/g" \
$(grep -Rsi 'pattern' path/to/dir/ | cut -d: -f1)
sed:
i in_place
e exec other command or script
grep:
R recursive
s Suppress error messages
i ignore case sensitive