LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-09-2013, 11:48 AM   #1
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Puzzling behavior of YES command


This code ...
Code:
echo; echo "Case 1"
yes ' -' |head -n4
echo; echo "Case 2"
yes '--' |head -n4
echo; echo "Case 3"
yes '- ' |head -n4
... produces this result ...
Code:
Case 1
 -
 -
 -
 -

Case 2
y
y
y
y

Case 3
yes: invalid option -- ' '
Try `yes --help' for more information.
Case 1 produces the expected result.
Case 2 produces an unexpected result, but didn't blow up.
Case 3 blows up.

Please advise.

Daniel B. Martin
 
Old 03-09-2013, 12:05 PM   #2
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
In case 1, the first (and only) argument starts with a blank, and so it is treated as a simple text string. In cases 2 & 3, however, it starts with the hyphen, meaning that the command tries to treat it as an option flag.

The '--' in case 2 is treated as the "last option" option, clearing the way for the non-option arguments. But since there are no following arguments it uses the default 'y'

In case 3 '- ' is simply an invalid argument.


The way around it is to always use '--' first when the first non-option argument starts with a hyphen.

Code:
yes -- '--' |head -n4

yes -- '- ' |head -n4
This is true of most commands. You'd do the same, for example, if you needed to rm a filename that started with a hyphen. See the common options section of info coreutils.


Edit: BTW, here's a quick&dirty way to get the same output using bash only. At least with low numbers of lines.
Code:
printf '%s\n' '- '{,,,}
The brace expansion expands into one hyphen string for each comma-separated blank space.

Last edited by David the H.; 03-09-2013 at 12:29 PM. Reason: some additions
 
1 members found this post helpful.
Old 03-09-2013, 01:46 PM   #3
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Original Poster
Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Thank you, David the H., for this explanation.

A follow-on question... I was groping around hoping to find a Linux equivalent for the REXX built-in function COPIES, and thought yes would serve. As you explained, that works for many character strings but not all.

This is how COPIES works:
Code:
COPIES('FOO',3)  returns 'FOOFOOFOO'        (Without the quote marks)
COPIES('*',16)   returns '****************' (Without the quote marks)
COPIES('Bar ',2) returns 'Bar Bar '         (Without the quote marks)
Is there a Linux command which suits this purpose?

Daniel B. Martin
 
Old 03-09-2013, 02:07 PM   #4
linosaurusroot
Member
 
Registered: Oct 2012
Distribution: OpenSuSE,RHEL,Fedora,OpenBSD
Posts: 982
Blog Entries: 2

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by danielbmartin View Post
Code:
COPIES('FOO',3)  returns 'FOOFOOFOO'        (Without the quote marks)
COPIES('*',16)   returns '****************' (Without the quote marks)
COPIES('Bar ',2) returns 'Bar Bar '         (Without the quote marks)
Is there a Linux command which suits this purpose?

Code:
perl -e 'print "Foo"x3; print "\n"'
 
1 members found this post helpful.
Old 03-09-2013, 02:19 PM   #5
H_TeXMeX_H
LQ Guru
 
Registered: Oct 2005
Location: $RANDOM
Distribution: slackware64
Posts: 12,928
Blog Entries: 2

Rep: Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301
Code:
bash-4.2$ copies() { for i in $(seq 1 "$2"); do printf "$1"; done }
bash-4.2$ copies FOO 3
FOOFOOFOObash-4.2$ 
bash-4.2$ copies '*' 16
****************bash-4.2$ 
bash-4.2$ copies 'Bar ' 2
Bar Bar bash-4.2$
 
1 members found this post helpful.
Old 03-09-2013, 02:29 PM   #6
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 852

Rep: Reputation: 389Reputation: 389Reputation: 389Reputation: 389
Slightly shorter printf solution:

Code:
printf "$s%.0s" $(seq 1 $n)
 
1 members found this post helpful.
Old 03-10-2013, 12:17 PM   #7
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Ruby is basically the same as perl in its format:
Code:
ruby -e 'puts "foo" * 3'
Awk is by no means short, but works:
Code:
awk 'BEGIN{OFS="foo";$3="foo";print}'
I would be curious, does REXX's function print the original examples as expected? I would assume yes as it is not shell environment using a command, such as yes.
 
1 members found this post helpful.
Old 03-10-2013, 12:35 PM   #8
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Original Poster
Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by grail View Post
Awk is by no means short, but works:
Code:
awk 'BEGIN{OFS="foo";$3="foo";print}'
Clever, I like it, and found a way to make it shorter.
This code ...
Code:
echo
awk 'BEGIN{OFS="foo";$3="foo";print}'
echo
awk 'BEGIN{OFS="foo";$4="";print}'
... produced this result ...
Code:
 
foofoofoo

foofoofoo
Daniel B. Martin
 
Old 03-10-2013, 01:32 PM   #9
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Original Poster
Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by grail View Post
I would be curious, does REXX's function print the original examples as expected?
I copied those three examples from the Regina manual. Regina is one of the Freeware implementations of REXX for the PC platform.

In response to your question I coded those examples in a trivial REXX program.
This code ...
Code:
say COPIES('FOO',3) 
say COPIES('*',16) 
say COPIES('Bar ',2)
... produced this result ...
Code:
FOOFOOFOO
****************
Bar Bar
(Note: say is equivalent to echo.)

Daniel B. Martin

Last edited by danielbmartin; 03-10-2013 at 01:33 PM. Reason: Correct grammatical error
 
Old 03-10-2013, 01:51 PM   #10
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Sorry Daniel, I was unclear, I meant the dash examples in the original question, but as I said, I would guess it would not be affected as it is not a command with switches, which is why "yes" was affected.
 
Old 03-10-2013, 02:56 PM   #11
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Original Poster
Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
(Inadvertent double post deleted.)

Last edited by danielbmartin; 03-10-2013 at 02:57 PM. Reason: (Inadvertent double post deleted.)
 
Old 03-10-2013, 03:04 PM   #12
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Original Poster
Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by grail View Post
... I meant the dash examples in the original question ...
This REXX code ...
Code:
say COPIES(' -',4) 
say COPIES('--',4) 
say COPIES('- ',4)
... produced this result ...
Code:
 - - - -
--------
- - - -
No idiosyncratic behavior because of dashes.

Daniel B. Martin
 
Old 03-10-2013, 07:31 PM   #13
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Original Poster
Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by David the H. View Post
The way around it is to always use '--' first when the first non-option argument starts with a hyphen.
Code:
yes -- '--' |head -n4

yes -- '- ' |head -n4
Several solutions have been offered and I like this best. Simple, straightforward, gets the job done. Thank you!

Daniel B. Martin
 
Old 03-11-2013, 01:28 PM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
> The way around it is to always use '--' first when the first non-option argument starts with a hyphen.

And when the argument is a parameter/variable:

Code:
someprogram -- "$1"
much safer.
 
2 members found this post helpful.
Old 03-12-2013, 08:51 AM   #15
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Well, if all you wanted was to duplicate a string 'n' times, you should've said so!

Code:
$ printf -v string '%03d' ; echo "${string//0/foo}"
foofoofoo
Edit: Here's the same thing wrapped up in a small function:

Code:
#$1 is the string to copy
#$2 is the number of times to print it (defaults to one)
copies(){
    local str
    printf -v str '%0*d' "${2:-1}"
    printf '%s\n' "${str//0/$1}"
}
The use of "*" in the %d format string tells it to use the value of the first argument as the padding number, rather than as a printing input.

Last edited by David the H.; 03-12-2013 at 09:10 AM. Reason: as stated
 
  


Reply

Tags
yes command



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Puzzling options of du command on AIX avijadhav AIX 8 06-08-2012 12:01 PM
Behavior of Command Line Expansion in touch command ahmedb72 Linux - Newbie 10 07-01-2009 02:51 AM
ls command behavior day4night Linux - Newbie 7 01-25-2004 12:57 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:42 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration